Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## Unreleased
* Add `getParentInstance()` API to `TaskOrchestrationContext` for discovering parent orchestration info ([#284](https://github.com/microsoft/durabletask-java/pull/284))

## v1.9.0
* Fix entity locking deserialization and add Jackson support for EntityInstanceId/EntityMetadata ([#281](https://github.com/microsoft/durabletask-java/pull/281))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.durabletask;

import java.util.Objects;
import javax.annotation.Nonnull;

/**
* Represents the parent orchestration of a sub-orchestration.
* This is available via {@link TaskOrchestrationContext#getParentInstance()} when the
* current orchestration was started as a sub-orchestration.
*/
public final class ParentOrchestrationInstance {
private final String name;
private final String instanceId;

/**
* Creates a new ParentOrchestrationInstance.
*
* @param name the name of the parent orchestration
* @param instanceId the instance ID of the parent orchestration
*/
public ParentOrchestrationInstance(@Nonnull String name, @Nonnull String instanceId) {
this.name = Objects.requireNonNull(name, "name");
this.instanceId = Objects.requireNonNull(instanceId, "instanceId");
}
Comment thread
bachuv marked this conversation as resolved.

/**
* Gets the name of the parent orchestration.
*
* @return the parent orchestration name
*/
@Nonnull
public String getName() {
return this.name;
}
Comment thread
bachuv marked this conversation as resolved.

/**
* Gets the instance ID of the parent orchestration.
*
* @return the parent orchestration instance ID
*/
@Nonnull
public String getInstanceId() {
return this.instanceId;
}

@Override
public String toString() {
return String.format("ParentOrchestrationInstance{name='%s', instanceId='%s'}", name, instanceId);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ParentOrchestrationInstance)) return false;
ParentOrchestrationInstance that = (ParentOrchestrationInstance) o;
return Objects.equals(name, that.name) && Objects.equals(instanceId, that.instanceId);
}

@Override
public int hashCode() {
return Objects.hash(name, instanceId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,19 @@ default Task<AutoCloseable> lockEntities(@Nonnull EntityInstanceId... entityIds)
*/
void clearCustomStatus();

/**
* Gets the parent orchestration instance, or {@code null} if this orchestration
* was not started as a sub-orchestration.
* <p>
* Implementers that wrap or decorate another {@link TaskOrchestrationContext}
* must delegate to the wrapped instance. Returning {@code null} unconditionally
* will incorrectly report sub-orchestrations as standalone.
*
* @return the parent orchestration instance, or {@code null}
*/
@Nullable
ParentOrchestrationInstance getParentInstance();

/**
* Makes a durable HTTP request using the specified {@link DurableHttpRequest} and returns a {@link Task}
* that completes when the HTTP call completes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ private class ContextImplTask implements TaskOrchestrationContext {
private boolean preserveUnprocessedEvents;
private Object customStatus;
private TraceContext parentTraceContext;
private ParentOrchestrationInstance parentInstance;

// Entity integration state (Phase 4)
private String executionId;
Expand Down Expand Up @@ -207,6 +208,12 @@ public String getInstanceId() {
return this.instanceId;
}

@Override
@Nullable
public ParentOrchestrationInstance getParentInstance() {
return this.parentInstance;
}

private void setInstanceId(String instanceId) {
// TODO: Throw if instance ID is not null
this.instanceId = instanceId;
Expand Down Expand Up @@ -1705,6 +1712,16 @@ private void processEvent(HistoryEvent e) {
} else {
this.parentTraceContext = null;
}
if (startedEvent.hasParentInstance()) {
ParentInstanceInfo parentInfo = startedEvent.getParentInstance();
String parentName = parentInfo.hasName() ? parentInfo.getName().getValue() : "";
String parentInstanceId = parentInfo.hasOrchestrationInstance()
? parentInfo.getOrchestrationInstance().getInstanceId()
: "";
this.parentInstance = new ParentOrchestrationInstance(parentName, parentInstanceId);
} else {
this.parentInstance = null;
}
TaskOrchestrationFactory factory = TaskOrchestrationExecutor.this.orchestrationFactories.get(name);
if (factory == null) {
// Try getting the default orchestrator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ static class RecordingContext implements TaskOrchestrationContext {
@Override
public String getInstanceId() { return "test-instance"; }

@Override
public ParentOrchestrationInstance getParentInstance() { return null; }

@Override
public Instant getCurrentInstant() { return Instant.now(); }

Expand Down
Loading
Loading