发生异常时,我正在将对象发送到服务器(顺序约90个)。端点关闭,Logback会触发自定义STMP附加程序,该附加程序最多只能发送1封电子邮件。 10个日志,然后有一个延迟,其他日志被发送。 start()
是否可能被频繁调用?
问题:
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
在执行一次后不会延迟,而直接在另一时间执行,因此一小时之内可以收到很多电子邮件。
我必须更改延迟的工作原理?
洪水图片(如您所见,不到1小时就收到了两封电子邮件...)
附加代码:
public class ScheduledSMTPAppender extends SMTPAppender {
private final ThreadFactory tf = r -> {
Thread t = new Thread(r, "ScheduledSMTPAppender Thread");
t.setDaemon(true); //make daemon or it will prevent your program to exit
return t;
};
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, tf);
private final List<ILoggingEvent> events = new ArrayList<>();
private int maxMessages = 10;
public ScheduledSMTPAppender() {
super();
}
public ScheduledSMTPAppender(EventEvaluator<ILoggingEvent> eventEvaluator) {
super(eventEvaluator);
}
@Override public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}
@Override protected void sendBuffer(CyclicBuffer<ILoggingEvent> cb, ILoggingEvent lastEventObject) {
events.add(lastEventObject);
if (events.size() > maxMessages)
{
sendEmail();
}
}
//needs to be synchronized for thread safety
private synchronized void sendEmail() {
try {
if (events.isEmpty()){
return;
}
ILoggingEvent lastEvent = events.get(events.size() - 1);
events.remove(events.size() - 1);
CyclicBuffer<ILoggingEvent> cb;
if (events.isEmpty()) {
cb = new CyclicBuffer<>(1);
} else {
cb = new CyclicBuffer<>(events.size());
for (ILoggingEvent e : events){
cb.add(e);
}
}
super.sendBuffer(cb, lastEvent);
events.clear();
} catch (Exception e) {
//Important to have a catch all here or the scheduled task will die
addError("Error occurred while sending e-mail notification.", e);
}
}
//this allows to make "maxMessages" a parameter of your appender
public int getMaxMessages() {
return maxMessages;
}
public String getContentType() {
return layout.getContentType();
}
public void setMaxMessages(int maxMessages) {
this.maxMessages = maxMessages;
}
答案 0 :(得分:3)
这似乎是问题所在
@Override
public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}
此调度程序将为每个初始化的附加程序将sendEmail任务排队。 您可以在每条日志行中记录对象的实例或一些ID,并在每次调用start时进行记录吗?那应该可以弄清楚情况。
请明确说明-我尝试了使用Sysout而不是记录器的相同代码(并在main方法中初始化了),并且按预期工作。这是代码
public class ScheduledSMTPAppender /*extends SMTPAppender*/ {
private static final ThreadFactory tf = r -> {
Thread t = new Thread(r, "ScheduledSMTPAppender Thread");
t.setDaemon(true); //make daemon or it will prevent your program to exit
return t;
};
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, tf);
private final List<String> events = new ArrayList<>();
private int maxMessages = 10;
public static void main(String args[]) {
ScheduledSMTPAppender app = new ScheduledSMTPAppender();
System.out.println("started");
Thread t = new Thread(() -> {
try {
scheduler.awaitTermination(1, TimeUnit.HOURS);
} catch (Exception e) {
}
});
System.out.println("awaiting termination");
t.start();
System.out.println("thread initiated");
new Thread(() -> {
// Thread to add events to check logs
for (int i =0;i<10;i++)
{app.addEvent("asd");
try {Thread.sleep(1000);
} catch(Exception e) {};}
}).start();
}
public ScheduledSMTPAppender() {
super();
System.out.println("starting");
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.SECONDS);
}
/*
public ScheduledSMTPAppender(EventEvaluator<String> eventEvaluator) {
super(eventEvaluator);
}
@Override
public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}*/
//@Override
protected void sendBuffer(List<String> cb, String lastEventObject) {
//System.out.println("sending email");
events.add(lastEventObject);
if (events.size() > maxMessages) {
sendEmail();
}
System.out.println(new Date() + "sent email" + lastEventObject);
}
//needs to be synchronized for thread safety
private synchronized void sendEmail() {
try {
if (events.isEmpty()) {
return;
}
String lastEvent = events.get(events.size() - 1);
events.remove(events.size() - 1);
List<String> cb;
if (events.isEmpty()) {
cb = new ArrayList<>(1);
} else {
cb = new ArrayList<>(events.size());
for (String e : events) {
cb.add(e);
}
}
sendBuffer(cb, lastEvent);
events.clear();
} catch (Exception e) {
//Important to have a catch all here or the scheduled task will die
//addError("Error occurred while sending e-mail notification.", e);
}
}
//this allows to make "maxMessages" a parameter of your appender
public int getMaxMessages() {
return maxMessages;
}
// public String getContentType() {
// return layout.getContentType();
// }
public void setMaxMessages(int maxMessages) {
this.maxMessages = maxMessages;
}
public void addEvent(String s) {
events.add(s);
}
}