288 lines
6.6 KiB
TypeScript
288 lines
6.6 KiB
TypeScript
/**
|
|
* Worker that Triggers and Manages Workflows
|
|
*
|
|
* Demonstrates:
|
|
* - Creating workflow instances
|
|
* - Querying workflow status
|
|
* - Sending events to workflows
|
|
* - Pausing/resuming workflows
|
|
* - Terminating workflows
|
|
*/
|
|
|
|
import { Hono } from 'hono';
|
|
|
|
type Bindings = {
|
|
MY_WORKFLOW: Workflow;
|
|
DB: D1Database;
|
|
};
|
|
|
|
const app = new Hono<{ Bindings: Bindings }>();
|
|
|
|
/**
|
|
* Create new workflow instance
|
|
*/
|
|
app.post('/workflows/create', async (c) => {
|
|
const body = await c.req.json<{
|
|
userId: string;
|
|
email: string;
|
|
[key: string]: any;
|
|
}>();
|
|
|
|
try {
|
|
// Create workflow instance with parameters
|
|
const instance = await c.env.MY_WORKFLOW.create({
|
|
params: body
|
|
});
|
|
|
|
// Optionally store instance ID for later reference
|
|
await c.env.DB.prepare(`
|
|
INSERT INTO workflow_instances (id, user_id, status, created_at)
|
|
VALUES (?, ?, ?, ?)
|
|
`).bind(
|
|
instance.id,
|
|
body.userId,
|
|
'queued',
|
|
new Date().toISOString()
|
|
).run();
|
|
|
|
return c.json({
|
|
id: instance.id,
|
|
status: await instance.status(),
|
|
createdAt: new Date().toISOString()
|
|
}, 201);
|
|
} catch (error) {
|
|
return c.json({
|
|
error: 'Failed to create workflow',
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get workflow instance status
|
|
*/
|
|
app.get('/workflows/:id', async (c) => {
|
|
const instanceId = c.req.param('id');
|
|
|
|
try {
|
|
const instance = await c.env.MY_WORKFLOW.get(instanceId);
|
|
const status = await instance.status();
|
|
|
|
return c.json({
|
|
id: instanceId,
|
|
...status
|
|
});
|
|
} catch (error) {
|
|
return c.json({
|
|
error: 'Workflow not found',
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
}, 404);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Send event to waiting workflow
|
|
*/
|
|
app.post('/workflows/:id/events', async (c) => {
|
|
const instanceId = c.req.param('id');
|
|
const body = await c.req.json<{
|
|
type: string;
|
|
payload: any;
|
|
}>();
|
|
|
|
try {
|
|
const instance = await c.env.MY_WORKFLOW.get(instanceId);
|
|
|
|
await instance.sendEvent({
|
|
type: body.type,
|
|
payload: body.payload
|
|
});
|
|
|
|
return c.json({
|
|
success: true,
|
|
message: 'Event sent to workflow'
|
|
});
|
|
} catch (error) {
|
|
return c.json({
|
|
error: 'Failed to send event',
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Pause workflow instance
|
|
*/
|
|
app.post('/workflows/:id/pause', async (c) => {
|
|
const instanceId = c.req.param('id');
|
|
|
|
try {
|
|
const instance = await c.env.MY_WORKFLOW.get(instanceId);
|
|
await instance.pause();
|
|
|
|
// Update database
|
|
await c.env.DB.prepare(`
|
|
UPDATE workflow_instances SET status = ? WHERE id = ?
|
|
`).bind('paused', instanceId).run();
|
|
|
|
return c.json({
|
|
success: true,
|
|
message: 'Workflow paused'
|
|
});
|
|
} catch (error) {
|
|
return c.json({
|
|
error: 'Failed to pause workflow',
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Resume paused workflow instance
|
|
*/
|
|
app.post('/workflows/:id/resume', async (c) => {
|
|
const instanceId = c.req.param('id');
|
|
|
|
try {
|
|
const instance = await c.env.MY_WORKFLOW.get(instanceId);
|
|
await instance.resume();
|
|
|
|
// Update database
|
|
await c.env.DB.prepare(`
|
|
UPDATE workflow_instances SET status = ? WHERE id = ?
|
|
`).bind('running', instanceId).run();
|
|
|
|
return c.json({
|
|
success: true,
|
|
message: 'Workflow resumed'
|
|
});
|
|
} catch (error) {
|
|
return c.json({
|
|
error: 'Failed to resume workflow',
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Terminate workflow instance
|
|
*/
|
|
app.post('/workflows/:id/terminate', async (c) => {
|
|
const instanceId = c.req.param('id');
|
|
|
|
try {
|
|
const instance = await c.env.MY_WORKFLOW.get(instanceId);
|
|
await instance.terminate();
|
|
|
|
// Update database
|
|
await c.env.DB.prepare(`
|
|
UPDATE workflow_instances SET status = ? WHERE id = ?
|
|
`).bind('terminated', instanceId).run();
|
|
|
|
return c.json({
|
|
success: true,
|
|
message: 'Workflow terminated'
|
|
});
|
|
} catch (error) {
|
|
return c.json({
|
|
error: 'Failed to terminate workflow',
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* List all workflow instances (with filtering)
|
|
*/
|
|
app.get('/workflows', async (c) => {
|
|
const status = c.req.query('status');
|
|
const userId = c.req.query('userId');
|
|
const limit = parseInt(c.req.query('limit') || '20');
|
|
const offset = parseInt(c.req.query('offset') || '0');
|
|
|
|
let query = 'SELECT * FROM workflow_instances WHERE 1=1';
|
|
const params: any[] = [];
|
|
|
|
if (status) {
|
|
query += ' AND status = ?';
|
|
params.push(status);
|
|
}
|
|
|
|
if (userId) {
|
|
query += ' AND user_id = ?';
|
|
params.push(userId);
|
|
}
|
|
|
|
query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
|
|
params.push(limit, offset);
|
|
|
|
try {
|
|
const results = await c.env.DB.prepare(query).bind(...params).all();
|
|
|
|
return c.json({
|
|
workflows: results.results,
|
|
limit,
|
|
offset,
|
|
total: results.results.length
|
|
});
|
|
} catch (error) {
|
|
return c.json({
|
|
error: 'Failed to list workflows',
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Health check
|
|
*/
|
|
app.get('/health', (c) => {
|
|
return c.json({
|
|
status: 'ok',
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
|
|
/**
|
|
* API documentation
|
|
*/
|
|
app.get('/', (c) => {
|
|
return c.json({
|
|
name: 'Workflow Management API',
|
|
version: '1.0.0',
|
|
endpoints: {
|
|
'POST /workflows/create': {
|
|
description: 'Create new workflow instance',
|
|
body: { userId: 'string', email: 'string', ...params: 'any' }
|
|
},
|
|
'GET /workflows/:id': {
|
|
description: 'Get workflow status',
|
|
params: { id: 'workflow instance ID' }
|
|
},
|
|
'POST /workflows/:id/events': {
|
|
description: 'Send event to workflow',
|
|
params: { id: 'workflow instance ID' },
|
|
body: { type: 'string', payload: 'any' }
|
|
},
|
|
'POST /workflows/:id/pause': {
|
|
description: 'Pause workflow',
|
|
params: { id: 'workflow instance ID' }
|
|
},
|
|
'POST /workflows/:id/resume': {
|
|
description: 'Resume paused workflow',
|
|
params: { id: 'workflow instance ID' }
|
|
},
|
|
'POST /workflows/:id/terminate': {
|
|
description: 'Terminate workflow',
|
|
params: { id: 'workflow instance ID' }
|
|
},
|
|
'GET /workflows': {
|
|
description: 'List workflows',
|
|
query: { status: 'string (optional)', userId: 'string (optional)', limit: 'number', offset: 'number' }
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
export default app;
|