PURISTA to Temporal
A Temporal workflow does not start by itself. There must be someone or something, which starts a specific workflow and provides the workflow input payload.
We will create a PURISTA command, which is exposed via the HTTP server, to start a workflow.
This allows us, to manually start workflows via the OpenAPI UI.
Create a command
Expecting we have a service called User
, we create a command register
with purista add command register
.
Ensure, you allready have set up the HTTP server and OpenAPI UI.
As next step, we will need to add the Temporal configuration to our service User
, to become available in our command register
. We need to extend our userServiceConfig.ts
import { z } from 'zod'
// define the service config schema and the default service configuration
export const userServiceV1ConfigSchema = z.object({
taskQueue: z.string(),
namespace: z.string(),
connect: z.object({
address: z.string(),
}),
})
export type UserServiceV1Config = z.input<typeof userServiceV1ConfigSchema>
In the main index.ts
, where we initiate the service instances, we need to provide the config.
import temporalConfig from './config/temporalConfig.js'
const userService = await userV1Service.getInstance(eventBridge, {
serviceConfig: { ...temporalConfig },
})
Now, we want to expose our newly created command and start a workflow.
We only need to add a few lines here in registerCommandBuilder.ts
import { randomUUID } from 'node:crypto'
import { Client, Connection } from '@temporalio/client'
import { ServiceEvent } from '../../../../ServiceEvent.enum.js'
import { userV1ServiceBuilder } from '../../userV1ServiceBuilder.js'
import {
userV1RegisterInputParameterSchema,
userV1RegisterInputPayloadSchema,
userV1RegisterOutputPayloadSchema,
} from './schema.js'
export const registerCommandBuilder = userV1ServiceBuilder
.getCommandBuilder('register', 'registers a new user')
.setSuccessEventName(ServiceEvent.UserRegistrationStarted)
.addPayloadSchema(userV1RegisterInputPayloadSchema)
.addParameterSchema(userV1RegisterInputParameterSchema)
.addOutputSchema(userV1RegisterOutputPayloadSchema)
.exposeAsHttpEndpoint('POST', 'register')
.disableHttpSecurity()
.setCommandFunction(async function ({ logger }, payload, _parameter) {
const connection = await Connection.connect(this.config.connect)
const client = new Client({
connection,
namespace: this.config.namespace,
})
const handle = await client.workflow.start('onboardingWorkflow', {
taskQueue: this.config.taskQueue,
args: [payload],
workflowId: randomUUID(),
})
logger.info(`Started workflow ${handle.workflowId}`)
await connection.close()
return {
payload,
workflowId: handle.workflowId
}
})
INFO
For simplicity, the connection to Temporal is directly done in the command on each request.
You might move this to the service via custom class.
Try out
- start the Temporal worker with
npm run dev:worker
- in a other cli start the PURISTA application with
npm run dev
- open the OpenAPI UI
You should now be able to call the register
endpoint with some payload.
The command will:
- connect to Temporal
- start the workflow
onboardingWorkflow
and pass the payload as argument to it - the workflow should be started and the workflow id is logged
- the command returns the input payload and the workflow id
The workflow id is some kind of instance id. Each run of a workflow, must have a unique id.
You can add some log output to src/temporal/workflows/onboardingWorkflow.ts
.
import { proxyActivities } from '@temporalio/workflow'
import type { ActivitiesType } from '../worker.js'
const { } = proxyActivities<ActivitiesType>({
startToCloseTimeout: '1 minute',
})
export async function onboardingWorkflow(input: unknown): Promise<void> {
console.log(input)
}
You can use the Temporal UI http://localhost:8080/ to view the workflows.