1

Recently, when using the asynchronous tasks that come with the COLA framework, I found that each execution of asynchronous tasks is executed twice. If some interfaces are not idempotent, there will be problems, such as warehousing operations, etc., will cause Data is repeatedly stored in the database, causing serious bugs.

With doubts, started the bug journey.

1 problem found

1. First check whether there are two execution entries, and only one is found;

2. The problem of calling the entrance? The handler was called directly through the controller, and it was called twice.

3. Simplify the code, delete all the content in the handler, and only have one logger print statement? The result was printed twice.

But this time, I found that the thread names of the logger are different, they are two threads.

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

2 Troubleshooting

Why are there two threads executing at the same time? View 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(() -> {
                    return p.execute(event);
                });
            }
        } catch (Exception var5) {
            response = this.handleException(p, response, var5);
        }

        return response;
    }).collect(Collectors.toList());
}

Submit the asynchronous task, and finally go to the above code, and submit the task to the thread pool for execution. If there is no custom thread pool, it will be submitted to the default thread pool of defaultExecutor

Found that it was submitted twice, check the content in this object, == found that Event object and Handler object have two ==.

图1-线程池对象

3 Cause of the problem

What causes duplicate objects?

Compared with the previous handler object, the only difference of this object is to use @RefreshScope , check the annotation source code, and find that the object with the annotation == will use the code to create a new object, and cache it ==, debug source code, view the cached object Object.

图2-Scope缓存对象

Found that there is indeed a TestHandler object, the object is @12349.

Compared with the handler object in Figure 1, there is also a TestHandler object inside, which is also @12349.

It turns out that because the annotation @RefreshScope , this annotation will create an object, so there will be two identical objects, causing repeated execution.

Conclusion: The use of annotation @RefreshScope requires attention. It is best to put the content of the configuration obtained in a separate property object, and do not mix it with other codes.


程序员伍六七
201 声望597 粉丝