You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug] Python agent’s @runnable does not behave as expected #11605
1、 when the service is started, it will try to obtain a snapshot before making method calls. The behavior is expected for an interpreted language like python.
But when the method is actually executed, an None snapshot will cause the trace to interrupt.
2、 After checking the test cases, the writing method in the picture below can behave as expected.
Each method call triggers snapshot = get_context().capture()
But we cannot require users to write this way
Are you willing to submit a pull request to fix on your own?
Yes I am willing to submit a pull request on my own!
The @runnable decorator captured the snapshot at decoration time (decorator() scope), not at execution time:
defdecorator(func):
snapshot=get_context().capture() # runs when @runnable is applied
When @runnable is applied at module level (the natural Python pattern shown in the issue):
@runnable(op="/post")defpost():
...
get_context().capture() runs at import time — no active trace exists, so snapshot is None. Later when the child thread runs, context.continued(None) is a no-op, and the cross-thread trace link is lost.
The existing test used @runnableinline inside a request handler, where the trace context was active at decoration time — that's why it passed.
How to write it to work (current version)
Define and decorate the function inside the request handler:
@app.route("/")defhello():
@runnable(op="/post") # decorated during request, snapshot is validdefpost():
...
thread=Thread(target=post)
thread.start()
return"ok"
post.continue_tracing() — called on the parent thread during the request, captures the snapshot, returns a callable that propagates the trace context to the child thread via CrossThread reference
post() — direct call still works as before (local span + decoration-time snapshot), fully backward compatible
The inline pattern also continues to work unchanged:
@app.route("/")defhello():
@runnable(op="/post") # snapshot captured here, during the requestdefpost():
...
thread=Thread(target=post) # no change neededthread.start()
return"ok"
No global monkey-patching of threading.Thread is involved.
Activity
feat: add sw_threading plugin for automatic cross-thread context prop…
wu-sheng commentedon Apr 12, 2026
Root Cause
The
@runnabledecorator captured the snapshot at decoration time (decorator()scope), not at execution time:When
@runnableis applied at module level (the natural Python pattern shown in the issue):get_context().capture()runs at import time — no active trace exists, so snapshot isNone. Later when the child thread runs,context.continued(None)is a no-op, and the cross-thread trace link is lost.The existing test used
@runnableinline inside a request handler, where the trace context was active at decoration time — that's why it passed.How to write it to work (current version)
Define and decorate the function inside the request handler:
Fix:
continue_tracing()API (apache/skywalking-python#391)@runnablenow returns a wrapper object with acontinue_tracing()method. Call it on the parent thread to capture the snapshot at the right moment:post.continue_tracing()— called on the parent thread during the request, captures the snapshot, returns a callable that propagates the trace context to the child thread via CrossThread referencepost()— direct call still works as before (local span + decoration-time snapshot), fully backward compatibleThe inline pattern also continues to work unchanged:
No global monkey-patching of
threading.Threadis involved.fix: support module-level @Runnable with continue_tracing() for cross…
fix: support module-level @Runnable with continue_tracing() (#391)