Recently, when using the asynchronous task provided by COLA framework, I found that asynchronous tasks are executed twice each time. If some asynchronous tasks are not implemented idempotent interfaces, there will be problems, such as the database entry operation, which will cause repeated data entry and serious bugs.

With doubts, began the bug journey.

1 Problem Discovery

1. First check whether there are two execution entrances and find only one;

2. Call entry problems? Call handler directly through controller, or call handler twice.

3, simplify the code, delete everything in handler, only one logger print statement? It was printed twice.

This time, however, the logger has two different thread names.

2021-07-26 14:11:19.429  INFO 47294 --- [pool-4-thread-2] c.e.colademo.event.handler.TestHandler   : >>>>>>>>>>>>> 0
2021-07-26 14:11:19.430  INFO 47294 --- [pool-4-thread-1] c.e.colademo.event.handler.TestHandler   : >>>>>>>>>>>>> 0
Copy the code

2 Troubleshooting

Why are two threads executing at the same time? Check the COLA source code.

public void asyncFire(EventI event) {
    this.eventHub.getEventHandler(event.getClass()).parallelStream().map((p) -> {
        Response response = null;

        try {
            if (null! = p.getExecutor()) { p.getExecutor().submit(() -> {return p.execute(event);
                });
            } else {
                this.defaultExecutor.submit(() -> {
                    returnp.execute(event); }); }}catch (Exception var5) {
            response = this.handleException(p, response, var5);
        }

        return response;
    }).collect(Collectors.toList());
}
Copy the code

Submitting an asynchronous task, which eventually goes to the code above, commits the task to the thread pool, or defaultExecutor, the default thread pool, if there is no custom thread pool.

The Event object and the Handler object both have two ==.

3 Causes

What causes duplicate objects?

The only difference between this object and the previous handler object is that the @refreshScope annotation is used to create a new object and cache it.

TestHandler object found, @12349.

Compare the Handler object in Figure 1, which also has a TestHandler object, also @12349.

That’s right, because of the @refreshScope annotation, which creates an object so that there are two identical objects, causing repeated execution.

Conclusion: Use the @refreshScope annotation to note that it is best to get the configuration in a separate property object and not mix it with other code.