mostafacs / quarkus-temporal-extension

Temporal workflow engine integration with quarkus
MIT License
16 stars 7 forks source link
java quarkus temporal temporal-extension temporal-workflow temporal-workflows temporalio

QUARKUS - TEMPORAL EXTENSION

With this extension you can easily implement a temporal workflow in your quarkus project. Review this demo for a quick start.

How to use ?

1- Add extension dependency to your maven POM file.

2- Updated netty-shaded on quarkus-bom

 <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-bom</artifactId>
            <version>${quarkus.platform.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- Only necessary while quarkus does not bump the netty-all lib. -->
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.39.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

3- Add temporal server url config in application.properties

quarkus.temporal.service.url=localhost:7233
quarkus.temporal.multi-tenant.enabled=false # false is the default

Enable multi-tenancy will init RequestContext before calling the activity method.

4- Add configuration file named workflow.yml to resources folder

Example

defaults:
  workflowExecutionTimeout: 20 # in minutes default is 60 minute if not set
  workflowRunTimeout: 15 # in minutes default is 60 minute
  workflowTaskTimeout: 14 # in minutes default is 60 minute

  activityScheduleToStartTimeout: 60 # in minutes default is 60 minute
  activityScheduleToCloseTimeout: 60 # in minutes default is 60 minute
  activityStartToCloseTimeout: 60 # in minutes default is 60 minute
  #heartbeat timeout must be shorter than START_TO_CLOSE timeout
  activityHeartBeatTimeout: 5 # in minutes default is 60 minute
  activityRetryInitInterval: 1 # in minutes default is 5 minute
  activityRetryMaxInterval: 1 # in minutes default is 1 minute if not set
  activityRetryBackOffCoefficient: 1.0  # default is 1.0
  activityRetryMaxAttempts: 5  # default is 1 attempt

# override defaults per workflow
workflows:
  test:
    executionTimeout: 2
    runTimeout: 2
    taskTimeout: 2
    activities:
      test:
        scheduleTostartTimeout: 10
        scheduleTocloseTimeout: 10
        #startTocloseTimeout: 20
        #heartbeatTimeout: 2
        #retryInitInterval: 1
        #retryMaxInterval: 1
        #retryMaxAttempts: 1

Declare your Temporal Activities:

    @ActivityInterface
    public interface TestActivity {

        String hello();
    }
    // name used to get the activity configurations from workflow.yml
    @TemporalActivity(name="test")
    public class TestActivityImpl implements TestActivity {

        // you can inject your services here.

        @Override
        public String hello() {
            return "I'm hello activity";
        }
    }

Declare your Temporal Workflows:

    @WorkflowInterface
    public interface TestWorkflow {

        @WorkflowMethod
        void run();
    }
    @TemporalWorkflow(queue = "testQueue", name="test")
    public class TestWorkflowImpl implements TestWorkflow {

        @TemporalActivityStub
        TestActivity testActivity;

        @Override
        public void run() {
            System.out.println(testActivity.hello());
            Workflow.sleep(10000);
            System.out.println("Workflow <<1>> completed");
        }
    }

Add your own interceptors (you can add many interceptors classes)

    @Singleton
    @Unremovable
    public class TemporalLoggingInterceptor implements WorkerInterceptor {

        @Override
        public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) {
            return new MyWorkflowInboundInterceptor(next);
        }

        @Override
        public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) {
            return new MyActivityInboundInterceptor(next);
        }

    }  

Run your workflow:


    @Path("/temporal-client")
    @ApplicationScoped
    public class TemporalClientController {

        @Inject
        WorkflowBuilder workflowBuilder;

        @GET
        public String hello() {
            TestWorkflow testWorkflow = workflowBuilder.build(TestWorkflow.class, "test123");
            WorkflowClient.execute(testWorkflow::run);
            return "workfow started";
        }
    }