-
Notifications
You must be signed in to change notification settings - Fork 258
fixed:issues #292 fatal error: concurrent map iteration and map write #346
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
I've looked into the code, but the ideal way to fix this issue is to avoid race condition to
So bad that they are running in 2 different goroutines, but this is not an issue to I can push directly into your branch if you don't mind, just fell free to tell what's your thoughts. |
Firstly, I strongly support a solution that fundamentally addresses the problem, rather than a temporary solution. The reality is that there are 3 goroutines related to issue # 292, not 2 goroutines
It should be noted that: If the goroutines problem is solved by merging the local_runtime.run.routine.Submit goroutines http_server.srv.ListenAndServe goroutines and base_stse.baseSSEService.routine.Submit goroutines ,I personally think the cost is relatively high! If that's the case, it will also have a significant impact on the new energy of dify_plugin_daemon. The above is just my personal opinion. If there are any questions, please continue to communicate and discuss. |
|
Actually, At this point, you can see that each request will create 2 goroutines which I've mentioned above, one is flowchart TD
%% First flow: http_server
A1[http_server.srv.ListenAndServe]
A2[createStream]
A3[setupHooks]
A4[listenToHttpEvents]
A1 --> A2 --> A3 --> A4
%% Second flow: base_sse
B1[base_sse.baseSSEService.routine.Submit]
B2[listenToStream]
B3[writeToSSE]
B1 --> B2 --> B3
%% Third flow: local_runtime with multiple requests
C1[local_runtime.run.routine.Submit]
C2a[request_1]
C2b[request_2]
C2c[request_3]
C1 --> C2a
C1 --> C2b
C1 --> C2c
There is almost no performance issue in the flow, they are just simply listen and write, of course I've created a flamegraph, almost all the CPU resource was used on serialization, and the limitation is GIL inside plugin itself, not here, that's how goroutine it should be, just like Okay, what's more, we have 3 types of plugins: Local/Serverless/Debugging, they have been uniformed to the same IO interfaces to keep the behaviour the same, based on the uniformed interfaces, the result is the flow above, the only routine will may could be merged was Yes I agree that we need a fundamental solution, that why I introduced
For Finally, lets back to the issue itself, this a |
Okay, I understand what you're saying. Avoiding goroutines competition is indeed a good solution. What I'm curious about is how to modify the code |
As described by # 292 Issuse, using both 'output_Schema' and 'create_variable_message' will verify whether the format of the data is correct.
However, the problem is that the read() and close() of the stream are executed by different goroutines. At this point, the plugin daemon receives an error message from the plugin ("SESSION_MESSAGE_TYPE_ERROR"), and then executes the stream's close(). Close() internally calls the stream's before Close callback function, while stream's read() calls the filter callback function. The problem lies here, the stream's before Close callback function and read () callback function access the critical resource variables (a map variable). This critical resource variable was accessed in multiple goroutines but was not protected, resulting in a 'concurrent map iteration and map write' error and ultimately causing the daemon to crash.
Simply put, the error message sent by dify-plugin triggered the crash bug of dify-plugin-daemon
Solution:
Use locks to protect critical resources