/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.falcon.rerun.queue;
import org.apache.commons.codec.CharEncoding;
import org.apache.falcon.FalconException;
import org.apache.commons.io.IOUtils;
import org.apache.falcon.aspect.GenericAlert;
import org.apache.falcon.rerun.event.RerunEvent;
import org.apache.falcon.rerun.event.RerunEventFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.DelayQueue;
/**
* An in-memory implementation of a DelayedQueue.
* @param <T>
*/
public class InMemoryQueue<T extends RerunEvent> extends DelayedQueue<T> {
public static final Logger LOG = LoggerFactory.getLogger(DelayedQueue.class);
protected DelayQueue<T> delayQueue = new DelayQueue<T>();
private final File serializeFilePath;
public InMemoryQueue(File serializeFilePath) {
this.serializeFilePath = serializeFilePath;
}
@Override
public boolean offer(T event) {
boolean flag = delayQueue.offer(event);
beforeRetry(event);
LOG.debug("Enqueued Message: {}", event.toString());
return flag;
}
@Override
public T take() throws FalconException {
T event;
try {
event = delayQueue.take();
LOG.debug("Dequeued Message: {}", event.toString());
afterRetry(event);
} catch (InterruptedException e) {
throw new FalconException(e);
}
return event;
}
public void populateQueue(List<T> events) {
for (T event : events) {
delayQueue.offer(event);
}
}
@Override
public void init() {
List<T> events = bootstrap();
populateQueue(events);
}
@Override
public void reconnect() throws FalconException {
//Do Nothing
}
private void beforeRetry(T event) {
File retryFile = getRetryFile(serializeFilePath, event);
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(retryFile, true)));
out.write(event.toString());
out.newLine();
out.close();
} catch (IOException e) {
LOG.warn("Unable to write entry for process-instance: {}:{}",
event.getEntityName(), event.getInstance(), e);
} finally {
IOUtils.closeQuietly(out);
}
}
private File getRetryFile(File basePath, T event) {
return new File(basePath, (event.getType().name()) + "-"
+ event.getEntityName() + "-"
+ event.getInstance().replaceAll(":", "-"));
}
private void afterRetry(T event) {
File retryFile = getRetryFile(serializeFilePath, event);
if (!retryFile.exists()) {
LOG.warn("Rerun file deleted or renamed for process-instance: {}:{}",
event.getEntityName(), event.getInstance());
GenericAlert.alertRetryFailed(event.getEntityType(), event.getEntityName(), event.getInstance(),
event.getWfId(), event.getWorkflowUser(), Integer.toString(event.getRunId()),
"Rerun file deleted or renamed for process-instance:");
} else {
if (!retryFile.delete()) {
LOG.warn("Unable to remove rerun file {}", event.getWfId());
retryFile.deleteOnExit();
}
}
}
private List<T> bootstrap() {
List<T> rerunEvents = new ArrayList<T>();
File[] files = serializeFilePath.listFiles();
if (files != null) {
for (File rerunFile : files) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(rerunFile)
, CharEncoding.UTF_8));
String line;
while ((line = reader.readLine()) != null) {
T event = new RerunEventFactory<T>().getRerunEvent(
rerunFile.getName(), line);
rerunEvents.add(event);
}
} catch (Exception e) {
LOG.warn("Not able to read rerun entry {}", rerunFile.getAbsolutePath(), e);
} finally {
IOUtils.closeQuietly(reader);
}
}
}
return rerunEvents;
}
}