Skip to content

🍒 8722 - Handle reentrant scope cleanup in Akka/Pekko actor instrumentations #8723

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

Merged
merged 1 commit into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,9 @@ class ContinuableScope implements AgentScope {

final Context context; // package-private so scopeManager can access it directly

/** Flag that this scope should be allowed to propagate across async boundaries. */
private static final byte ASYNC_PROPAGATING = 1;
private boolean asyncPropagating;

/** Flag that we intend to roll back the scope stack to this scope in the future. */
private static final byte CHECKPOINTED = 2;

private byte flags;
private short checkpointCount = 0;

private final byte source;

Expand All @@ -37,12 +33,12 @@ class ContinuableScope implements AgentScope {
final ContinuableScopeManager scopeManager,
final Context context,
final byte source,
final boolean isAsyncPropagating,
final boolean asyncPropagating,
final Stateful scopeState) {
this.scopeManager = scopeManager;
this.context = context;
this.source = source;
this.flags = isAsyncPropagating ? ASYNC_PROPAGATING : 0;
this.asyncPropagating = asyncPropagating;
this.scopeState = scopeState;
}

Expand Down Expand Up @@ -121,7 +117,7 @@ final boolean alive() {

@Override
public final boolean isAsyncPropagating() {
return (flags & ASYNC_PROPAGATING) != 0;
return asyncPropagating;
}

@Override
Expand All @@ -136,11 +132,7 @@ public Context context() {

@Override
public final void setAsyncPropagation(final boolean value) {
if (value) {
flags |= ASYNC_PROPAGATING;
} else {
flags &= ~ASYNC_PROPAGATING;
}
asyncPropagating = value;
}

@Override
Expand All @@ -149,13 +141,13 @@ public final String toString() {
}

public void checkpoint() {
flags |= CHECKPOINTED;
checkpointCount++;
}

public boolean rollback() {
if ((flags & CHECKPOINTED) != 0) {
flags &= ~CHECKPOINTED;
return false;
if (checkpointCount > 0) {
checkpointCount--;
return false; // stop rollback at checkpoint
} else {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,63 @@ class ScopeManagerTest extends DDCoreSpecification {
scopeManager.activeSpan() == null
}

def "rollback stops at most recent checkpoint"() {
when:
def span1 = tracer.buildSpan("test1", "test1").start()
def span2 = tracer.buildSpan("test2", "test2").start()
def span3 = tracer.buildSpan("test3", "test3").start()
then:
scopeManager.activeSpan() == null

when:
tracer.checkpointActiveForRollback()
tracer.activateSpan(span1)
tracer.checkpointActiveForRollback()
tracer.activateSpan(span2)
tracer.checkpointActiveForRollback()
tracer.activateSpan(span1)
tracer.checkpointActiveForRollback()
tracer.activateSpan(span2)
tracer.checkpointActiveForRollback()
tracer.activateSpan(span2)
tracer.checkpointActiveForRollback()
tracer.activateSpan(span1)
tracer.activateSpan(span2)
tracer.activateSpan(span3)
then:
scopeManager.activeSpan() == span3

when:
tracer.rollbackActiveToCheckpoint()
then:
scopeManager.activeSpan() == span2

when:
tracer.rollbackActiveToCheckpoint()
then:
scopeManager.activeSpan() == span2

when:
tracer.rollbackActiveToCheckpoint()
then:
scopeManager.activeSpan() == span1

when:
tracer.rollbackActiveToCheckpoint()
then:
scopeManager.activeSpan() == span2

when:
tracer.rollbackActiveToCheckpoint()
then:
scopeManager.activeSpan() == span1

when:
tracer.rollbackActiveToCheckpoint()
then:
scopeManager.activeSpan() == null
}

boolean spanFinished(AgentSpan span) {
return ((DDSpan) span)?.isFinished()
}
Expand Down