Skip to content

[Bug] Python agent’s @runnable does not behave as expected #11605

Closed
apache/skywalking-python
#391

Description

@xlq20080808

Search before asking

  • I had searched in the issues and found no similar issues.

Apache SkyWalking Component

Python Agent (apache/skywalking-python)

What happened

python version : 3.11.4
python agent : v1.0.1
flask version: 2.3.0

demo
image

cross threads are not in one trace
image

What you expected to happen

Cross threads in one trace
As shown below
image

How to reproduce

@app.route("/")
def hello():
    thread = threading.Thread(target=post)
    thread.start()
    return "ok"

@runnable(op="/post")
def post():
    return "post ok"

Anything else

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.
image
But when the method is actually executed, an None snapshot will cause the trace to interrupt.
image
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()
image
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!

Code of Conduct

Activity

  1. added
    bugSomething isn't working and you are sure it's a bug!
    on Nov 28, 2023
  2. added
    pluginPlugin for agent or collector. Be used to extend the capabilities of default implementor.
    on Nov 28, 2023
  3. added this to the python - 1.3.0 milestone on Apr 12, 2026
  4. self-assigned this
    on Apr 12, 2026
  5. added a commit that references this issue on Apr 12, 2026
    8b5df98
  6. wu-sheng commented on Apr 12, 2026

    @wu-sheng
    Member

    Root Cause

    The @runnable decorator captured the snapshot at decoration time (decorator() scope), not at execution time:

    def decorator(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")
    def post():
        ...

    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 @runnable inline 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("/")
    def hello():
        @runnable(op="/post")  # decorated during request, snapshot is valid
        def post():
            ...
        thread = Thread(target=post)
        thread.start()
        return "ok"

    Fix: continue_tracing() API (apache/skywalking-python#391)

    @runnable now returns a wrapper object with a continue_tracing() method. Call it on the parent thread to capture the snapshot at the right moment:

    from skywalking.decorators import runnable
    
    @runnable(op="/post")
    def post():
        requests.post('http://provider:9091/users')
    
    @app.route("/")
    def hello():
        thread = Thread(target=post.continue_tracing())  # snapshot captured here
        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("/")
    def hello():
        @runnable(op="/post")  # snapshot captured here, during the request
        def post():
            ...
        thread = Thread(target=post)  # no change needed
        thread.start()
        return "ok"

    No global monkey-patching of threading.Thread is involved.

  7. added a commit that references this issue on Apr 12, 2026
    10d5e18
  8. added a commit that references this issue on Apr 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working and you are sure it's a bug!pluginPlugin for agent or collector. Be used to extend the capabilities of default implementor.pythonPython agent related

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions