@@ -65,6 +65,12 @@ public interface InspectInfoActivity {
6565 ActivityInfoSnapshot inspectInfo ();
6666 }
6767
68+ @ ActivityInterface
69+ public interface AsyncCompletionActivity {
70+ @ ActivityMethod (name = "AsyncCompletion" )
71+ String complete ();
72+ }
73+
6874 @ ActivityInterface
6975 public interface EchoVoidActivity {
7076 @ ActivityMethod (name = "Echo1" )
@@ -110,6 +116,10 @@ public void execute() {}
110116 */
111117 private static volatile CountDownLatch cancelLatch ;
112118
119+ private static volatile CountDownLatch asyncStartLatch ;
120+ private static volatile String asyncActivityId ;
121+ private static volatile String asyncActivityRunId ;
122+
113123 public static class WaitForCancelActivityImpl implements WaitForCancelActivity {
114124 @ Override
115125 public void waitForCancel () {
@@ -127,6 +137,19 @@ public void waitForCancel() {
127137 }
128138 }
129139
140+ public static class AsyncCompletionActivityImpl implements AsyncCompletionActivity {
141+ @ Override
142+ public String complete () {
143+ ActivityInfo info = Activity .getExecutionContext ().getInfo ();
144+ asyncActivityId = info .getActivityId ();
145+ asyncActivityRunId = info .getActivityRunId ();
146+ Activity .getExecutionContext ().doNotCompleteOnReturn ();
147+ CountDownLatch latch = asyncStartLatch ;
148+ if (latch != null ) latch .countDown ();
149+ return null ;
150+ }
151+ }
152+
130153 public static class InspectInfoActivityImpl implements InspectInfoActivity {
131154 @ Override
132155 public ActivityInfoSnapshot inspectInfo () {
@@ -171,6 +194,7 @@ public String concat(String a, String b) {
171194 new SimpleActivityImpl (),
172195 new VoidActivityImpl (),
173196 new WaitForCancelActivityImpl (),
197+ new AsyncCompletionActivityImpl (),
174198 new InspectInfoActivityImpl (),
175199 new EchoVoidActivityImpl (),
176200 new ConcatActivityImpl ())
@@ -698,6 +722,58 @@ public void testExecuteAsyncWithMethodRef() throws Exception {
698722 assertEquals ("echo:async" , fut .get ());
699723 }
700724
725+ @ Test
726+ public void testCompletionClientStandaloneCompleteByActivityId () throws InterruptedException {
727+ assumeTrue (SDKTestWorkflowRule .useExternalService );
728+ asyncStartLatch = new CountDownLatch (1 );
729+ try {
730+ ActivityClient client = newActivityClient ();
731+ ActivityHandle <String > handle =
732+ client .start (
733+ AsyncCompletionActivity .class ,
734+ AsyncCompletionActivity ::complete ,
735+ simpleOpts (uniqueId ()));
736+
737+ assertTrue ("Activity did not start within 30s" , asyncStartLatch .await (30 , TimeUnit .SECONDS ));
738+
739+ client
740+ .newActivityCompletionClient ()
741+ .complete (asyncActivityId , Optional .empty (), "ext-result" );
742+
743+ assertEquals ("ext-result" , handle .getResult ());
744+ } finally {
745+ asyncStartLatch = null ;
746+ asyncActivityId = null ;
747+ asyncActivityRunId = null ;
748+ }
749+ }
750+
751+ @ Test
752+ public void testCompletionClientStandaloneCompleteWithRunId () throws InterruptedException {
753+ assumeTrue (SDKTestWorkflowRule .useExternalService );
754+ asyncStartLatch = new CountDownLatch (1 );
755+ try {
756+ ActivityClient client = newActivityClient ();
757+ ActivityHandle <String > handle =
758+ client .start (
759+ AsyncCompletionActivity .class ,
760+ AsyncCompletionActivity ::complete ,
761+ simpleOpts (uniqueId ()));
762+
763+ assertTrue ("Activity did not start within 30s" , asyncStartLatch .await (30 , TimeUnit .SECONDS ));
764+
765+ client
766+ .newActivityCompletionClient ()
767+ .complete (asyncActivityId , Optional .of (asyncActivityRunId ), "ext-result-with-run" );
768+
769+ assertEquals ("ext-result-with-run" , handle .getResult ());
770+ } finally {
771+ asyncStartLatch = null ;
772+ asyncActivityId = null ;
773+ asyncActivityRunId = null ;
774+ }
775+ }
776+
701777 // ---------------------------------------------------------------------------
702778 // Interceptor helpers
703779 // ---------------------------------------------------------------------------
0 commit comments