代码之家  ›  专栏  ›  技术社区  ›  Alan

自定义SMTPAppender中的scheduleAtFixedRate执行线程太频繁

  •  0
  • Alan  · 技术社区  · 6 年前

    start() 调用太频繁?

    问题:
    scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);

    我需要做什么来改变调度程序的延迟工作?

    调试之后我注意到 Attaching appender named [EMAIL] to Logger[ROOT] 发生了两次。这可能是问题所在,如果是,我该如何解决?

    洪水图片(如你所见,两封邮件在一小时内发送…)
    Floof

    Logback.xml配置:

    <configuration debug="true">
    
    <!-- Logging per console and per email -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                <!-- sets the format of the output -->
                %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
            </Pattern>
        </layout>
    </appender>
    
    <appender name="EMAIL" class="com.konverto.phonebillasaj.appenders.ScheduledSMTPAppender">
        <subject>TESTING: %logger{20} - %m</subject>
        <layout class="ch.qos.logback.classic.html.HTMLLayout" />
    
        <smtpHost>smtp.xxx.net</smtpHost>
        <smtpPort>587</smtpPort>
        <STARTTLS>true</STARTTLS>
        <username>xxx@domain.net</username>
        <password>myPass</password>
        <to>yyy@domain.net</to>
        <from>xxx@domain.net</from>
        <maxMessages>10</maxMessages>
    
        <!-- for testing , comment in production, default 256 -->
        <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
            <!-- Send just one log entry per email, ready for a lot of emails if you put one. -->
            <bufferSize>1</bufferSize>
        </cyclicBufferTracker>
    
        <!-- for testing , comment in production, default asynchronousSending = true -->
        <asynchronousSending>false</asynchronousSending>
    </appender>
    
    
    <logger name="com.konverto.phonebillasaj" level="error" additivity="false">
        <appender-ref ref="EMAIL"/>
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <root level="error">
        <appender-ref ref="EMAIL" />
        <appender-ref ref="CONSOLE" />
    </root>
    

    附件编码:

    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 回复  |  直到 6 年前
        1
  •  3
  •   Aditya    6 年前

    这似乎是个问题

    @Override 
    public void start() {
        super.start();
        scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
    }
    

    此计划程序将为初始化的每个追加程序排队发送电子邮件任务。 你能将对象的实例或某个id记录在每个日志行中,并且每次调用start时记录吗?这应该可以澄清这种情况。

    为了清楚起见,我用Sysout代替了logger(并在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);
        }
    }