diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93a0d2144b..8867f08d72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@v4 - + - name: Run unit tests env: USER: unittest @@ -152,7 +152,7 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@v4 - + - name: Run cloud test # Only supported in non-fork runs, since secrets are not available in forks. We intentionally # are only doing this check on the step instead of the job so we require job passing in CI @@ -191,10 +191,10 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@v4 - + - name: Run copyright and code format checks run: ./gradlew --no-daemon spotlessCheck - + build_native_images: name: Build native test server uses: ./.github/workflows/build-native-image.yml diff --git a/temporal-sdk/src/main/java/io/temporal/worker/WorkerFactory.java b/temporal-sdk/src/main/java/io/temporal/worker/WorkerFactory.java index b33c2a331e..fb2311209e 100644 --- a/temporal-sdk/src/main/java/io/temporal/worker/WorkerFactory.java +++ b/temporal-sdk/src/main/java/io/temporal/worker/WorkerFactory.java @@ -4,6 +4,8 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.uber.m3.tally.Scope; +import io.temporal.api.workflowservice.v1.DescribeNamespaceRequest; +import io.temporal.api.workflowservice.v1.DescribeNamespaceResponse; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.common.converter.DataConverter; @@ -196,9 +198,14 @@ public synchronized void start() { // Workers check and require that Temporal Server is available during start to fail-fast in case // of configuration issues. - // TODO(https://github.com/temporalio/sdk-java/issues/2060) consider using describeNamespace as - // a connection check. - workflowClient.getWorkflowServiceStubs().getServerCapabilities(); + DescribeNamespaceResponse response = + workflowClient + .getWorkflowServiceStubs() + .blockingStub() + .describeNamespace( + DescribeNamespaceRequest.newBuilder() + .setNamespace(workflowClient.getOptions().getNamespace()) + .build()); for (Worker worker : workers.values()) { worker.start(); diff --git a/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java b/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java index e228508376..856ba8dcce 100644 --- a/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java +++ b/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java @@ -1,9 +1,14 @@ package io.temporal.workerFactory; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.serviceclient.WorkflowServiceStubsOptions; import io.temporal.worker.WorkerFactory; @@ -128,4 +133,24 @@ public void factoryCanBeShutdownMoreThanOnce() { factory.shutdown(); factory.awaitTermination(1, TimeUnit.MILLISECONDS); } + + @Test + public void startFailsOnNonexistentNamespace() { + WorkflowServiceStubs serviceLocal = + WorkflowServiceStubs.newServiceStubs( + WorkflowServiceStubsOptions.newBuilder().setTarget(serviceAddress).build()); + WorkflowClient clientLocal = + WorkflowClient.newInstance( + serviceLocal, WorkflowClientOptions.newBuilder().setNamespace("i_dont_exist").build()); + WorkerFactory factoryLocal = WorkerFactory.newInstance(clientLocal); + factoryLocal.newWorker("task-queue"); + + StatusRuntimeException ex = assertThrows(StatusRuntimeException.class, factoryLocal::start); + assertEquals(Status.Code.NOT_FOUND, ex.getStatus().getCode()); + + factoryLocal.shutdownNow(); + factoryLocal.awaitTermination(5, TimeUnit.SECONDS); + serviceLocal.shutdownNow(); + serviceLocal.awaitTermination(5, TimeUnit.SECONDS); + } } diff --git a/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java b/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java index a21380b9c1..93d489d7ec 100644 --- a/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java +++ b/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java @@ -11,6 +11,7 @@ import io.temporal.common.WorkflowExecutionHistory; import io.temporal.spring.boot.autoconfigure.workerversioning.TestWorkflow; import io.temporal.spring.boot.autoconfigure.workerversioning.TestWorkflow2; +import io.temporal.worker.WorkerFactory; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -20,7 +21,7 @@ import org.springframework.test.context.ActiveProfiles; @SpringBootTest(classes = WorkerVersioningTest.Configuration.class) -@ActiveProfiles(profiles = "worker-versioning") +@ActiveProfiles(profiles = {"worker-versioning", "disable-start-workers"}) @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class WorkerVersioningTest { @Autowired ConfigurableApplicationContext applicationContext; @@ -43,6 +44,12 @@ void setUp() { @Test @Timeout(value = 10) public void testAutoDiscovery() { + // Manually start the worker because we disable automatic worker start, due to + // automatic worker start running prior to the docker check, which causes namespace + // errors when running in-mem unit tests + WorkerFactory workerFactory = applicationContext.getBean(WorkerFactory.class); + workerFactory.start(); + workflowClient .getWorkflowServiceStubs() .blockingStub()