Skip to content

Commit eff3ca2

Browse files
Merge Nexus into Master (#2270)
Nexus Support to the Java SDK
1 parent af7b5b7 commit eff3ca2

File tree

158 files changed

+10784
-190
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

158 files changed

+10784
-190
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ ext {
3232
// Platforms
3333
grpcVersion = '1.54.1' // [1.38.0,) Needed for io.grpc.protobuf.services.HealthStatusManager
3434
jacksonVersion = '2.14.2' // [2.9.0,)
35+
nexusVersion = '0.2.0-alpha'
3536
// we don't upgrade to 1.10.x because it requires kotlin 1.6. Users may use 1.10.x in their environments though.
3637
micrometerVersion = project.hasProperty("edgeDepsTest") ? '1.10.5' : '1.9.9' // [1.0.0,)
3738

docker/github/docker-compose.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ services:
3434
- "6934:6934"
3535
- "6935:6935"
3636
- "6939:6939"
37+
- "7243:7243"
3738
environment:
3839
- "CASSANDRA_SEEDS=cassandra"
3940
- "ENABLE_ES=true"
4041
- "ES_SEEDS=elasticsearch"
4142
- "DYNAMIC_CONFIG_FILE_PATH=config/dynamicconfig/development.yaml"
43+
- "FRONTEND_HTTP_PORT=7243"
4244
depends_on:
4345
- cassandra
4446
- elasticsearch

docker/github/dynamicconfig/development.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,12 @@ history.MaxBufferedQueryCount:
1919
worker.buildIdScavengerEnabled:
2020
- value: true
2121
worker.removableBuildIdDurationSinceDefault:
22-
- value: 1
22+
- value: 1
23+
system.enableNexus:
24+
- value: true
25+
component.nexusoperations.callback.endpoint.template:
26+
- value: http://localhost:7243/namespaces/{{.NamespaceName}}/nexus/callback
27+
component.callbacks.allowedAddresses:
28+
- value:
29+
- Pattern: "localhost:7243"
30+
AllowInsecure: true
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.workflow
22+
23+
import io.temporal.kotlin.TemporalDsl
24+
25+
/**
26+
* @see NexusOperationOptions
27+
*/
28+
inline fun NexusOperationOptions(
29+
options: @TemporalDsl NexusOperationOptions.Builder.() -> Unit
30+
): NexusOperationOptions {
31+
return NexusOperationOptions.newBuilder().apply(options).build()
32+
}
33+
34+
/**
35+
* Create a new instance of [NexusOperationOptions], optionally overriding some of its properties.
36+
*/
37+
inline fun NexusOperationOptions.copy(
38+
overrides: @TemporalDsl NexusOperationOptions.Builder.() -> Unit
39+
): NexusOperationOptions {
40+
return toBuilder().apply(overrides).build()
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.workflow
22+
23+
import io.temporal.kotlin.TemporalDsl
24+
25+
/**
26+
* @see NexusServiceOptions
27+
*/
28+
inline fun NexusServiceOptions(
29+
options: @TemporalDsl NexusServiceOptions.Builder.() -> Unit
30+
): NexusServiceOptions {
31+
return NexusServiceOptions.newBuilder().apply(options).build()
32+
}
33+
34+
/**
35+
* Create a new instance of [NexusServiceOptions], optionally overriding some of its properties.
36+
*/
37+
inline fun NexusServiceOptions.copy(
38+
overrides: @TemporalDsl NexusServiceOptions.Builder.() -> Unit
39+
): NexusServiceOptions {
40+
return toBuilder().apply(overrides).build()
41+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.nexus
22+
23+
import io.temporal.workflow.NexusOperationOptions
24+
import org.junit.Assert.assertEquals
25+
import org.junit.Test
26+
import java.time.Duration
27+
28+
class NexusOperationOptionsExtTest {
29+
30+
@Test
31+
fun `OperationOptions DSL should be equivalent to builder`() {
32+
val dslOperationOptions = NexusOperationOptions {
33+
setScheduleToCloseTimeout(Duration.ofMinutes(1))
34+
}
35+
36+
val builderOperationOptions = NexusOperationOptions.newBuilder()
37+
.setScheduleToCloseTimeout(Duration.ofMinutes(1))
38+
.build()
39+
40+
assertEquals(builderOperationOptions, dslOperationOptions)
41+
}
42+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.nexus
22+
23+
import io.temporal.workflow.NexusOperationOptions
24+
import io.temporal.workflow.NexusServiceOptions
25+
import org.junit.Assert.assertEquals
26+
import org.junit.Test
27+
import java.time.Duration
28+
29+
class NexusServiceOptionsExtTest {
30+
31+
@Test
32+
fun `ServiceOptions DSL should be equivalent to builder`() {
33+
val dslServiceOptions = NexusServiceOptions {
34+
setEndpoint("TestEndpoint")
35+
setOperationOptions(
36+
NexusOperationOptions {
37+
setScheduleToCloseTimeout(Duration.ofMinutes(1))
38+
}
39+
)
40+
setOperationMethodOptions(
41+
mapOf(
42+
"test" to NexusOperationOptions {
43+
setScheduleToCloseTimeout(Duration.ofMinutes(2))
44+
}
45+
)
46+
)
47+
}
48+
49+
val builderServiceOptions = NexusServiceOptions.newBuilder()
50+
.setEndpoint("TestEndpoint")
51+
.setOperationOptions(
52+
NexusOperationOptions.newBuilder()
53+
.setScheduleToCloseTimeout(Duration.ofMinutes(1))
54+
.build()
55+
)
56+
.setOperationMethodOptions(
57+
mapOf(
58+
"test" to NexusOperationOptions.newBuilder()
59+
.setScheduleToCloseTimeout(Duration.ofMinutes(2))
60+
.build()
61+
)
62+
)
63+
.build()
64+
65+
assertEquals(builderServiceOptions, dslServiceOptions)
66+
}
67+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.workflow
22+
23+
import io.nexusrpc.Operation
24+
import io.nexusrpc.Service
25+
import io.nexusrpc.handler.OperationContext
26+
import io.nexusrpc.handler.OperationHandler
27+
import io.nexusrpc.handler.OperationImpl
28+
import io.nexusrpc.handler.OperationStartDetails
29+
import io.nexusrpc.handler.ServiceImpl
30+
import io.nexusrpc.handler.SynchronousOperationFunction
31+
import io.temporal.client.WorkflowClientOptions
32+
import io.temporal.client.WorkflowOptions
33+
import io.temporal.common.converter.DefaultDataConverter
34+
import io.temporal.common.converter.JacksonJsonPayloadConverter
35+
import io.temporal.common.converter.KotlinObjectMapperFactory
36+
import io.temporal.internal.async.FunctionWrappingUtil
37+
import io.temporal.internal.sync.AsyncInternal
38+
import io.temporal.testing.internal.SDKTestWorkflowRule
39+
import org.junit.Assert.assertTrue
40+
import org.junit.Rule
41+
import org.junit.Test
42+
import java.time.Duration
43+
44+
class KotlinAsyncNexusTest {
45+
46+
@Rule
47+
@JvmField
48+
var testWorkflowRule: SDKTestWorkflowRule = SDKTestWorkflowRule.newBuilder()
49+
.setWorkflowTypes(WorkflowImpl::class.java)
50+
.setNexusServiceImplementation(TestNexusServiceImpl())
51+
.setWorkflowClientOptions(
52+
WorkflowClientOptions.newBuilder()
53+
.setDataConverter(DefaultDataConverter(JacksonJsonPayloadConverter(KotlinObjectMapperFactory.new())))
54+
.build()
55+
)
56+
.build()
57+
58+
@Service
59+
interface TestNexusService {
60+
@Operation
61+
fun operation(): String?
62+
}
63+
64+
@ServiceImpl(service = TestNexusService::class)
65+
class TestNexusServiceImpl {
66+
@OperationImpl
67+
fun operation(): OperationHandler<Void, String> {
68+
// Implemented inline
69+
return OperationHandler.sync<Void, String>(
70+
SynchronousOperationFunction<Void, String> { ctx: OperationContext, details: OperationStartDetails, _: Void? -> "Hello Kotlin" }
71+
)
72+
}
73+
}
74+
75+
@WorkflowInterface
76+
interface TestWorkflow {
77+
@WorkflowMethod
78+
fun execute()
79+
}
80+
81+
class WorkflowImpl : TestWorkflow {
82+
override fun execute() {
83+
val nexusService = Workflow.newNexusServiceStub(
84+
TestNexusService::class.java,
85+
NexusServiceOptions {
86+
setOperationOptions(
87+
NexusOperationOptions {
88+
setScheduleToCloseTimeout(Duration.ofSeconds(10))
89+
}
90+
)
91+
}
92+
)
93+
assertTrue(
94+
"This has to be true to make Async.function(nexusService::operation) work correctly as expected",
95+
AsyncInternal.isAsync(nexusService::operation)
96+
)
97+
assertTrue(
98+
"This has to be true to make Async.function(nexusService::operation) work correctly as expected",
99+
AsyncInternal.isAsync(FunctionWrappingUtil.temporalJavaFunctionalWrapper(nexusService::operation))
100+
)
101+
Async.function(nexusService::operation).get()
102+
}
103+
}
104+
105+
@Test
106+
fun asyncNexusWorkflowTest() {
107+
val client = testWorkflowRule.workflowClient
108+
val options = WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.taskQueue).build()
109+
val workflowStub = client.newWorkflowStub(TestWorkflow::class.java, options)
110+
workflowStub.execute()
111+
}
112+
}

temporal-sdk/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ dependencies {
88
api project(':temporal-serviceclient')
99
api "com.google.code.gson:gson:$gsonVersion"
1010
api "io.micrometer:micrometer-core"
11+
api "io.nexusrpc:nexus-sdk:$nexusVersion"
1112

1213
implementation "com.google.guava:guava:$guavaVersion"
1314
api "com.fasterxml.jackson.core:jackson-databind"

temporal-sdk/src/main/java/io/temporal/client/WorkflowClientInternalImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import io.temporal.common.interceptors.WorkflowClientCallsInterceptor;
3838
import io.temporal.common.interceptors.WorkflowClientInterceptor;
3939
import io.temporal.internal.WorkflowThreadMarker;
40+
import io.temporal.internal.client.NexusStartWorkflowRequest;
4041
import io.temporal.internal.client.RootWorkflowClientInvoker;
4142
import io.temporal.internal.client.WorkerFactoryRegistry;
4243
import io.temporal.internal.client.WorkflowClientInternal;
@@ -567,4 +568,16 @@ public void registerWorkerFactory(WorkerFactory workerFactory) {
567568
public void deregisterWorkerFactory(WorkerFactory workerFactory) {
568569
workerFactoryRegistry.deregister(workerFactory);
569570
}
571+
572+
@Override
573+
public WorkflowExecution startNexus(NexusStartWorkflowRequest request, Functions.Proc workflow) {
574+
enforceNonWorkflowThread();
575+
WorkflowInvocationHandler.initAsyncInvocation(InvocationType.START_NEXUS, request);
576+
try {
577+
workflow.apply();
578+
return WorkflowInvocationHandler.getAsyncInvocationResult(WorkflowExecution.class);
579+
} finally {
580+
WorkflowInvocationHandler.closeAsyncInvocation();
581+
}
582+
}
570583
}

0 commit comments

Comments
 (0)