Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webhooks): add webhook workflows #106

Merged
merged 91 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
fc310b9
feat(webhooks): add webhook workflows
steebchen May 20, 2024
5d83915
action
steebchen May 20, 2024
ef0a62c
multi lib
steebchen May 20, 2024
d18c751
seed dev
steebchen May 20, 2024
190e571
re-enable worker test
steebchen May 20, 2024
08162e2
upgrade hatchet
steebchen May 20, 2024
3ffdb0c
simplify test
steebchen May 20, 2024
bdee20e
improve handlers
steebchen May 24, 2024
dd8ab27
Merge remote-tracking branch 'origin/main' into webhooks
steebchen May 24, 2024
ebbe6f5
implement new webhook handler
steebchen May 25, 2024
a019a33
make webhook handlers synchrounous
steebchen May 25, 2024
1578fee
improve handler
steebchen Jun 10, 2024
264a649
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 10, 2024
d116b8d
chore(version): re-generate code and fix linter issues
steebchen Jun 10, 2024
59ac516
Merge branch 'main' into webhooks
steebchen Jun 10, 2024
36774bd
cleanup
steebchen Jun 10, 2024
9212091
register webhook
steebchen Jun 10, 2024
d8ee58f
Merge branch 'main' into webhooks
steebchen Jun 10, 2024
49ac3fb
update
steebchen Jun 10, 2024
b633f4d
fixes
steebchen Jun 10, 2024
3efe571
upgrade
steebchen Jun 10, 2024
9cdec5e
bump
steebchen Jun 10, 2024
fc5bd1c
improve actionType type
steebchen Jun 10, 2024
6404ee4
temp parse base64 json action payload
steebchen Jun 11, 2024
b011c6e
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 11, 2024
9d909a1
make handle action and step run handlers async
steebchen Jun 11, 2024
a695082
healthcheck response
steebchen Jun 11, 2024
921470e
fix webhook test
steebchen Jun 11, 2024
3789c38
fix unit tests
steebchen Jun 11, 2024
bbddd2a
update
steebchen Jun 11, 2024
443a354
temp jest detect open handles
steebchen Jun 11, 2024
015d263
add logs
steebchen Jun 11, 2024
7ae80d3
generate
steebchen Jun 11, 2024
e3ed921
reduce e2e timeout
steebchen Jun 11, 2024
76eeb4f
temp run serially
steebchen Jun 11, 2024
2a60e05
????
steebchen Jun 11, 2024
079955a
upgrade
steebchen Jun 12, 2024
f80a8ef
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 12, 2024
322df0c
adapt express handler healthcheck response
steebchen Jun 12, 2024
19ff89e
automatically register workflows
steebchen Jun 12, 2024
2856004
update
steebchen Jun 13, 2024
fe3d7f3
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 13, 2024
bca2adb
Update package.json
abelanger5 Jun 14, 2024
9cf39e7
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 18, 2024
c9e26a0
bump
steebchen Jun 18, 2024
204609f
fully asyncify handleStartStepRun
steebchen Jun 18, 2024
560ed72
adapt publish:ci command with alpha tag
steebchen Jun 18, 2024
7f278a5
fix result of run
steebchen Jun 18, 2024
537f40c
bump to 0.8.0-alpha.2
steebchen Jun 18, 2024
3ff5497
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 18, 2024
6a07428
Merge branch 'main' into webhooks
steebchen Jun 18, 2024
0a80efb
update hatchet & adapt healthchecks
steebchen Jun 18, 2024
871015d
automatically register workflows
steebchen Jun 20, 2024
40e20dc
bump to 0.8.0-alpha.3
steebchen Jun 20, 2024
36bab2c
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 20, 2024
b11f10d
refactor test names
steebchen Jun 20, 2024
0891ff0
logs
steebchen Jun 20, 2024
5c6decf
Revert "logs"
steebchen Jun 21, 2024
1ebfdc7
refactor handle, check for signature everywhere
steebchen Jun 21, 2024
1ca5d21
upgrade
steebchen Jun 24, 2024
12806e5
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 25, 2024
26eacf8
upgrade & adapt
steebchen Jun 25, 2024
d54eef2
remove unused PUT
steebchen Jun 25, 2024
0d29d04
attempt fix e2e test
steebchen Jun 25, 2024
dd297aa
adapt handler & upgrade
steebchen Jun 26, 2024
ba598ff
Merge remote-tracking branch 'origin/main' into webhooks
steebchen Jun 26, 2024
a1be65e
bump to 0.8.0-alpha.4
steebchen Jun 26, 2024
c7584a0
revert ActionObject changes
steebchen Jun 26, 2024
4f5ab1b
attempt to fix e2e tests
abelanger5 Jun 26, 2024
f3abdef
tmp: print response data
abelanger5 Jun 26, 2024
517078f
fix: bump hatchet v
abelanger5 Jun 26, 2024
8d068ce
rename registerWebhook
steebchen Jun 26, 2024
a11e78a
regen data contracts and print request
abelanger5 Jun 26, 2024
929412b
Merge branch 'webhooks' of github.com:hatchet-dev/hatchet-typescript …
abelanger5 Jun 26, 2024
cee1a21
tmp: print request url/method
abelanger5 Jun 26, 2024
ea5fd3e
fix: another log
abelanger5 Jun 26, 2024
c9e8e55
update
steebchen Jun 26, 2024
82a7cb9
Merge remote-tracking branch 'origin/webhooks' into webhooks
steebchen Jun 26, 2024
f575b49
remove base64 hack
steebchen Jun 26, 2024
811128a
fix: actually use generated config
abelanger5 Jun 26, 2024
a168518
Merge branch 'webhooks' of github.com:hatchet-dev/hatchet-typescript …
abelanger5 Jun 26, 2024
36ff50c
fix test migration
abelanger5 Jun 26, 2024
29c5766
fix prisma-migrate
abelanger5 Jun 26, 2024
bbf4b1e
fix: install atlas
abelanger5 Jun 26, 2024
349d0a7
fix: bashism
abelanger5 Jun 26, 2024
8151f5a
fix: path to certs
abelanger5 Jun 26, 2024
3da0284
log from steps
abelanger5 Jun 26, 2024
c4fe3d4
bump hatchet version
abelanger5 Jun 27, 2024
4a2e4c8
remove webhook e2e check for now
abelanger5 Jun 27, 2024
f628bc7
chore: versioning
abelanger5 Jun 27, 2024
3cfeda6
remove jest flags
abelanger5 Jun 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"plugins": ["@typescript-eslint", "import", "unused-imports", "prettier", "eslint-plugin-jest"],
"rules": {
"no-void": "off",
"@typescript-eslint/no-shadow": "off",
"@typescript-eslint/no-throw-literal": "off",
"no-use-before-define": "off",
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:

e2e:
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -83,7 +83,7 @@ jobs:
run: |
export DATABASE_URL="postgresql://hatchet:hatchet@127.0.0.1:5431/hatchet"
go run github.com/steebchen/prisma-client-go migrate deploy
task generate-all
go run github.com/steebchen/prisma-client-go generate
task generate-certs
task generate-local-encryption-keys

Expand Down Expand Up @@ -112,6 +112,8 @@ jobs:
SERVER_AUTH_SET_EMAIL_VERIFIED=true
EOF

export SEED_DEVELOPMENT=true

go run ./cmd/hatchet-admin quickstart

go run ./cmd/hatchet-engine --config ./generated/ &
Expand Down
96 changes: 96 additions & 0 deletions examples/webhooks.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { createServer } from 'node:http';
import { Workflow, Worker } from '../src';
import sleep from '../src/util/sleep';
import Hatchet from '../src/sdk';

const port = 8369;

describe('webhooks', () => {
let hatchet: Hatchet;
let worker: Worker;

beforeEach(async () => {
hatchet = Hatchet.init();
worker = await hatchet.worker('simple-webhook-workflow');
});

afterEach(async () => {
await worker.stop();
await sleep(2000);
});

it('should pass a webhook workflow', async () => {
let invoked = 0;

const workflow: Workflow = {
id: 'simple-webhook-workflow',
description: 'test',
on: {
event: 'user:create-webhook',
},
steps: [
{
name: 'step1',
run: async (ctx) => {
invoked += 1;
return { message: `${ctx.workflowName()} results!` };
},
},
{
name: 'step2',
parents: ['step1'],
run: (ctx) => {
invoked += 1;
return { message: `${ctx.workflowName()} results!` };
},
},
],
};

console.log('registering workflow...');
await worker.registerWorkflow(workflow);

const secret = 'secret';

console.log('registering webhook...');
await worker.registerWebhook({
secret,
url: `http://localhost:${port}/webhook`,
workflows: ['simple-webhook-workflow'],
});

console.log('starting worker...');

const handler = hatchet.webhooks(workflow);

const server = createServer(handler.httpHandler({ secret }));

await new Promise((resolve) => {
server.listen(port, () => {
resolve('');
});
});

console.log('server started.');
console.log('waiting for webhook to be registered...');

// wait for engine to pick up the webhook worker
await sleep(30000 + 3000);

console.log('webhook wait time complete.');

console.log('pushing event...');

await hatchet.event.push('user:create-webhook', {
test: 'test',
});

await sleep(10000);

console.log('invoked', invoked);

expect(invoked).toEqual(2);

await worker.stop();
}, 60000);
});
2 changes: 1 addition & 1 deletion hatchet
Submodule hatchet updated 48 files
+4 −79 .github/workflows/build.yml
+26 −337 .github/workflows/pre-release.yaml
+1 −1 Taskfile.yaml
+8 −0 api-contracts/openapi/components/schemas/_index.yaml
+51 −0 api-contracts/openapi/components/schemas/webhook_worker.yaml
+4 −0 api-contracts/openapi/openapi.yaml
+88 −0 api-contracts/openapi/paths/webhook-worker/webhook-worker.yaml
+51 −0 api/v1/server/handlers/webhook-worker/create.go
+33 −0 api/v1/server/handlers/webhook-worker/list.go
+13 −0 api/v1/server/handlers/webhook-worker/service.go
+389 −160 api/v1/server/oas/gen/openapi.gen.go
+14 −0 api/v1/server/oas/transformers/webhook_worker.go
+15 −12 api/v1/server/run/run.go
+15 −0 cmd/hatchet-engine/engine/run.go
+69 −0 examples/webhook/main.go
+110 −0 examples/webhook/main_e2e_test.go
+171 −0 examples/webhook/run.go
+35 −0 frontend/app/src/lib/api/generated/Api.ts
+29 −0 frontend/app/src/lib/api/generated/data-contracts.ts
+12 −1 frontend/app/src/lib/api/queries.ts
+6 −0 frontend/app/src/pages/main/index.tsx
+253 −0 frontend/app/src/pages/main/tenant-settings/webhooks/components/create-webhook-worker-dialog.tsx
+137 −0 frontend/app/src/pages/main/tenant-settings/webhooks/index.tsx
+11 −0 frontend/app/src/router.tsx
+1 −1 internal/config/loader/loader.go
+1 −1 internal/config/server/server.go
+44 −0 internal/randstr/randstr.go
+15 −0 internal/repository/prisma/dbsqlc/models.go
+42 −0 internal/repository/prisma/dbsqlc/schema.sql
+6 −0 internal/repository/prisma/repository.go
+1 −1 internal/repository/prisma/tenant.go
+92 −0 internal/repository/prisma/webhook_worker.go
+1 −0 internal/repository/repository.go
+22 −0 internal/repository/webhook_worker.go
+228 −0 internal/services/webhooks/webhooks.go
+18 −0 internal/signature/sign.go
+33 −0 internal/signature/sign_test.go
+14 −14 pkg/client/dispatcher.go
+335 −0 pkg/client/rest/gen.go
+47 −0 pkg/webhook/worker.go
+143 −0 pkg/worker/webhook_handler.go
+18 −7 pkg/worker/worker.go
+110 −0 pkg/worker/worker_webhook.go
+41 −0 prisma/migrations/20240610202350_wip/migration.sql
+40 −13 prisma/schema.prisma
+12 −0 sql/migrations/20240610202358_wip.sql
+2 −1 sql/migrations/atlas.sum
+42 −0 sql/schema/schema.sql
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"prepare": "npm run build",
"tsc:build": "tsc && resolve-tspaths",
"test:unit": "jest --testMatch='**/*.test.ts'",
"test:e2e": "jest --testMatch='**/*.e2e.ts'",
"test:e2e": "jest --testMatch='**/*.e2e.ts' --detectOpenHandles",
"test:unit:watch": "jest --testMatch='**/*.test.ts' --watch",
"generate": "pnpm run '/generate-.*/'",
"generate-api": "npx --yes swagger-cli bundle ./hatchet/api-contracts/openapi/openapi.yaml --outfile openapi.yaml --type yaml && npx swagger-typescript-api -p openapi.yaml -o src/clients/rest/generated -n hatchet.ts --modular --axios",
Expand Down Expand Up @@ -100,4 +100,4 @@
"yaml": "^2.3.4",
"zod": "^3.22.4"
}
}
}
6 changes: 5 additions & 1 deletion src/clients/admin/admin-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Logger } from '@hatchet/util/logger';
import { retrier } from '@hatchet/util/retrier';

import { Api } from '../rest';
import { WorkflowRunStatus } from '../rest/generated/data-contracts';
import { WebhookWorkerCreateRequest, WorkflowRunStatus } from '../rest/generated/data-contracts';

type WorkflowMetricsQuery = {
workflowId?: string;
Expand Down Expand Up @@ -90,6 +90,10 @@ export class AdminClient {
}
}

async webhook_create(data: WebhookWorkerCreateRequest) {
steebchen marked this conversation as resolved.
Show resolved Hide resolved
return this.api.webhookCreate(this.tenantId, data);
}

/**
* Run a new instance of a workflow with the given input. This will create a new workflow run and return the ID of the
* new run.
Expand Down
37 changes: 22 additions & 15 deletions src/clients/dispatcher/action-listener.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { DispatcherClient as PbDispatcherClient, AssignedAction } from '@hatchet/protoc/dispatcher';
import {
DispatcherClient as PbDispatcherClient,
AssignedAction,
actionTypeFromJSON,
} from '@hatchet/protoc/dispatcher';

import { Status } from 'nice-grpc';
import { ClientConfig } from '@clients/hatchet-client/client-config';
import sleep from '@util/sleep';
import HatchetError from '@util/errors/hatchet-error';
import { Logger } from '@hatchet/util/logger';

import { z } from 'zod';
import { DispatcherClient } from './dispatcher-client';
import { Heartbeat } from './heartbeat/heartbeat-controller';

Expand All @@ -18,20 +23,22 @@ enum ListenStrategy {
LISTEN_STRATEGY_V2 = 2,
}

export interface Action {
tenantId: string;
jobId: string;
jobName: string;
jobRunId: string;
stepId: string;
stepRunId: string;
actionId: string;
actionType: number;
actionPayload: string;
workflowRunId: string;
getGroupKeyRunId: string;
stepName: string;
}
export const ActionObject = z.object({
tenantId: z.string(),
abelanger5 marked this conversation as resolved.
Show resolved Hide resolved
jobId: z.string(),
jobName: z.string(),
jobRunId: z.string(),
stepId: z.string(),
stepRunId: z.string(),
actionId: z.string(),
actionType: z.preprocess((s) => actionTypeFromJSON(s), z.number().optional()),
actionPayload: z.string(),
workflowRunId: z.string(),
getGroupKeyRunId: z.string().optional(),
stepName: z.string(),
});

export type Action = z.infer<typeof ActionObject>;

export class ActionListener {
config: ClientConfig;
Expand Down
8 changes: 8 additions & 0 deletions src/clients/hatchet-client/hatchet-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,12 @@ export class HatchetClient {

return worker;
}

webhooks(workflow: Workflow) {
const worker = new Worker(this, {
name: workflow.id,
});

return worker.getHandler(workflow);
}
}
35 changes: 35 additions & 0 deletions src/clients/rest/generated/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ import {
UserLoginRequest,
UserRegisterRequest,
UserTenantMembershipsList,
WebhookWorker,
WebhookWorkerCreateRequest,
WebhookWorkerListResponse,
Worker,
WorkerList,
Workflow,
Expand Down Expand Up @@ -1636,4 +1639,36 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
format: 'json',
...params,
});
/**
* @description Lists all webhooks
*
* @name WebhookList
* @summary List webhooks
* @request GET:/api/v1/webhook-workers/{tenant}
* @secure
*/
webhookList = (tenant: string, params: RequestParams = {}) =>
this.request<WebhookWorkerListResponse, APIErrors>({
path: `/api/v1/webhook-workers/${tenant}`,
method: 'GET',
secure: true,
format: 'json',
...params,
});
/**
* @description Creates a webhook
*
* @name WebhookCreate
* @summary Create a webhook
* @request POST:/api/v1/webhook-workers/{tenant}/create
*/
webhookCreate = (tenant: string, data: WebhookWorkerCreateRequest, params: RequestParams = {}) =>
this.request<WebhookWorker, APIErrors>({
path: `/api/v1/webhook-workers/${tenant}/create`,
method: 'POST',
body: data,
type: ContentType.Json,
format: 'json',
...params,
});
}
29 changes: 29 additions & 0 deletions src/clients/rest/generated/data-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1014,3 +1014,32 @@ export interface WorkflowMetrics {
/** The total number of concurrency group keys. */
groupKeyCount?: number;
}

export interface WebhookWorker {
metadata: APIResourceMeta;
/** The webhook url. */
url: string;
/** The secret key for validation. */
secret: string;
}

export interface WebhookWorkerCreateRequest {
/** The webhook url. */
url: string;
/** The workflow IDs or names to register for this webhook worker. */
workflows: string[];
/**
* The secret key for validation. If not provided, a random secret will be generated.
* @minLength 32
*/
secret?: string;
}

export interface WebhookWorkerCreateResponse {
worker?: WebhookWorker;
}

export interface WebhookWorkerListResponse {
pagination?: PaginationResponse;
rows?: WebhookWorker[];
}
Loading
Loading