Repository navigation
Conversation
abb6426 to
54fdea4
Compare
|
Working to solve the open issue mentioned in the PR's description. |
| -- ============================================================================ | ||
|
|
||
| ALTER TABLE workflow_instances ADD COLUMN raw_event JSONB; | ||
| ALTER TABLE task_instances ADD COLUMN raw_event JSONB; |
There was a problem hiding this comment.
Why can't vector insert into the fields directly instead?
There was a problem hiding this comment.
The vector postgresql sink does not support ON CONFLIC the UPSERT approach (only INSERT for now).
Investigated the |
| @@ -0,0 +1,197 @@ | |||
| -- ============================================================================ | |||
| -- Direct normalized-table inserts (replaces V1's raw staging tables) | |||
There was a problem hiding this comment.
We can reuse the same since we haven't release it yet.
| inputs: [route_by_type.workflow_events] | ||
| source: | | ||
| . = { "tag": .flow_event.eventType, "time": now(), "data": .flow_event } | ||
| . = { "raw_event": .flow_event } |
There was a problem hiding this comment.
The idea is not to add to a raw column, but to map directly to the table here. If it's to keep the raw data, we keep the table. Keeping the table is complex, since we will need to implement a GC, or the tables will grow indefinitely with duplicated data.
Vector now inserts directly into workflow_instances/task_instances (raw_event JSONB column only), and the normalization triggers move onto those same tables via an INSERT ... ON CONFLICT DO UPDATE guarded by pg_trigger_depth() to prevent the nested self-insert from recursing.
Vector extracts and types each field in VRL instead of shipping raw_event JSONB; triggers read NEW.<column> directly. Adds from_event to distinguish Vector inserts from direct writers (JPA), fixes a stuck-status comparison, and always keeps from_event accurate on merge.
Changes
Builds on #73. Vector now inserts directly into
workflow_instances/task_instancesinstead of the raw staging tables, and the normalization triggers move onto those same tables (self-targetingINSERT ... ON CONFLICT DO UPDATE, guarded bypg_trigger_depth()to avoid recursion).Closes #74
Load test
Load test script + results: mcruzdev/k6-scripts
MODE 1 k6 results: before vs after
afteris on par or slightly better across the board.never_appeared_failuresroughly doubled (13→24 out of ~2200). Single trial each — needs repeat runs to confirm signal vs noise.Follow-up: typed-column inserts (RATE=60, 90s stress)
How-to test the changes
Below you can see how to test the entire change with a real Kubernetes cluster with KinD.
Step-by-step walkthrough to manually verify direct normalized-table inserts for MODE 1
Starting Colima:
1. Create the KIND cluster
Maps
localhost:30080(GraphQL),localhost:30082(workflow app),localhost:30432(Postgres).2. Build + load the MODE 1 images
Check docker images:
3. Install the chart (Postgres + Vector + triggers)
Confirm one
vectorDaemonSet, nofluentbit:4. Wait for pods
PostgreSQL:
kubectl wait -n postgresql --for=condition=ready pod/postgresql-0 --timeout=180sVector:
kubectl wait -n logging --for=condition=ready pod -l app=vector --timeout=180sData Index Service:
kubectl wait -n default --for=condition=ready pod -l app=data-index-service --timeout=300sWorkflow Test App:
kubectl wait -n workflows --for=condition=ready pod -l app=workflow-test-app --timeout=300s5. Verify the infrastructure
Expect: Vector running, GraphQL ready, 2 tables (
workflow_instances,task_instances— no moreworkflow_events_raw/task_events_raw), 2 triggers, now defined directly on those 2 tables instead of on the removed raw tables.NOTE: If you got some "Timed out." you can restart the
daemonset/vector:6. Turn on event tracing (optional)
kubectl set env daemonset/vector -n logging DEBUG_EVENTS=true(leave that streaming in another terminal)
7. Trigger a workflow
Traced Vector output should now show lines shaped
{"raw_event":{...}}(previously{"tag":"...","time":"...","data":{...}}) — Vector no longer computes atag/timeenvelope, it hands the untouched event straight to the sink underraw_event.8. Verify normalized tables (written directly by Vector, populated by the self-targeting triggers)
Expect the workflow row
status = COMPLETEDand its task rows, eachraw_eventholding the most recently applied event's JSON (latest event only, not full history — that's the trade-off for dropping the raw staging tables).Confirm the raw tables are really gone:
Expect
0.9. Verify the GraphQL API
WorkflowInstance/TaskExecutionfields:id name namespace version status startedAt endedAt lastUpdate eventTimestamp inputData outputData error{ ... } taskExecutions{ ... }. Introspect with{ __type(name:"WorkflowInstance"){ fields{ name } } }. No GraphQL schema changes in this PR —raw_eventisn't exposed.10. Idempotency spot-check (optional)
Expect:
0 rows— the trigger'sINSERT ... ON CONFLICT DO UPDATEmerges repeated events into the same row instead of inserting duplicates.11. Out-of-order spot-check (optional)
Confirms a task event that beats its workflow's own event still resolves correctly (via the trigger's proactive placeholder-workflow insert):
12. Concurrency spot-check (optional but recommended)
This is the actual scenario that broke in earlier testing of this PR: the
postgres_workflowandpostgres_tasksinks are separate, concurrent connections, and a task event racing a batch of workflow events for the sameinstanceIdproduced aduplicate key value violates unique constraint "workflow_instances_pkey"error that silently dropped the whole workflow-event batch (visible as an empty/placeholder-onlyworkflow_instancesrow despitetask_instanceshaving real data). Confirms the fix (INSERT ... ON CONFLICT+pg_trigger_depth()guard) holds under real concurrent writes:Expect no
duplicate keyerror from either background job, and a single fully-populatedworkflow_instancesrow (status = COMPLETED,name = race-test,output = {"r": 1}) — not an empty placeholder.Expect a placeholder
workflow_instancesrow (namespace/statusNULL) and a normaltask_instancesrow.13. Cleanup
Config source of truth:
data-index/collectors/vector/mode1-postgresql/vector.yaml.Full reference:
data-index/data-index-docs/modules/ROOT/pages/deployment/vector-config.adoc.