Repository navigation
Billing: emit compute usage MeterRecord per execution - #23858
DylanTinianov wants to merge 21 commits into
Conversation
|
✅ No conflicts with other open PRs targeting |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Failed emissions are logged as successful, and disabled metering leaks confidential execution marks.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Risk Rating: MEDIUM
Adds per-execution compute usage metering for workflow v2 engines, including confidential-execution exclusion and billing reconciliation logs.
Changes:
- Wires capability usage metering into workflow engines.
- Emits compute usage for successful and failed executions.
- Tracks confidential executions to avoid duplicate billing.
Scrupulous human review: ResourceManager failure reporting and confidential tracking lifecycle.
| File | Description |
|---|---|
core/services/workflows/v2/config.go |
Adds usage metering configuration. |
core/services/workflows/v2/confidential_module.go |
Tracks confidential executions. |
core/services/workflows/v2/compute_usage_test.go |
Tests compute usage emission. |
core/services/workflows/v2/base_engine.go |
Emits compute usage records. |
core/services/workflows/syncer/v2/handler.go |
Wires and manages the usage meter. |
core/services/cre/cre.go |
Creates the feature-gated ResourceManager. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…on (CRE-6779) When [Metering].CapabilityUsageEnabled is set, the syncer builds a ResourceManager and every v2 engine emits one METER_ACTION_USAGE record per execution after computeDuration is known: - resource type cre:workflow:compute, value in milliseconds - Utilization.ResourceId "<workflow_id>:<execution_id>", EventId = execution id (identical on every node; billing derives cre:workflow:<wf>:<exec>:<exec>) - Identity.Service workflow-engine, DON id from the local node, org from the engine's resolved org id Emitted for successful and failed executions, outside the legacy metering block so a legacy metering failure cannot suppress it, and skipped when the execution was delegated to the confidential module (ConfidentialModule now tracks the executions it handled; the enclave path meters those). Each emission logs "Emitted capability usage meter record" with executionID, eventID, resourceType, value and orgID. That line is a contract for the billing reconciler and is covered by a unit test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ntract Identity.ResourcePool and ResourcePoolID are now "cre:workflow:compute", derived via resourcemanager.WithWorkflowUsagePool, matching the Billing <-> Decentralized stack contract. Bumps chainlink-common. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… CapabilityUsageEnabled chainlink-common #2428 dropped the separate CapabilityUsageEnabled flag per review: capability usage records share the existing [Metering].MeterRecordsEnabled gate with durable resource metering. The syncer now builds the compute usage ResourceManager when MeterRecordsEnabled is set, next to the spec meter. Bumps chainlink-common to 16997122620e in all modules: CRE-6781-emit-usage-value merged with develop's current pin 8fdc7816. Re-bump to main once #2428 and the develop bump #23910 land. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
6527b3a to
b11eb78
Compare
…ink-common to ae91aba3 (#2457, confidential execution duration) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nsume confidential mark unconditionally, paralleltest/gci Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
When [Metering].MeterRecordsEnabled is on, the syncer hands every v2 engine a ResourceManager and the engine emits one cre:workflow:compute METER_ACTION_USAGE record per execution, for successful and failed runs, outside the legacy isMetering block and fail-open. The metered duration is what the module that ran the workflow reports on ExecutionResult.compute_duration_ms (chainlink-protos #472/#473, chainlink-common #2464): the WASM host's guest run, or for ConfidentialModule the enclave-measured execution_duration_ms. The engine falls back to its own wall-clock only when nothing was reported, so it no longer tracks which executions were delegated to the enclave, and the DON-time suspension tracker is gone; waits inside the run count as compute the same way capability waits already did. Every emission logs "Emitted capability usage meter record" with executionID, eventID, resourceType, value, orgID; that line is the contract for the billing reconciler. Bump chainlink-common to eff4aa59 and chainlink-protos/cre/go to 94b3b3de across all modules; add changeset. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
df1da62 to
aedb5c2
Compare
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
3b0e667 to
b58f8d2
Compare
The WASM host inside the enclave sets it on the ExecutionResult, so the response's execution_duration_ms is no longer copied. Bump chainlink-common. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…l-clock fallback Routes a TEE trigger through RequirementSelectingModule and ConfidentialModule to a mocked confidential-workflows capability and asserts the record carries the enclave-set compute_duration_ms, not the round trip; and that a module reporting no duration is metered from the engine's wall-clock. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The engine builds its ResourceManager from EngineConfig.MeterRecordsEnabled and UsageIdentity (UsageEmitter overrides beholder for tests); the syncer handler only forwards the identity via WithUsageMetering. Pin chainlink-protos/cre/go to the main merge of #473 and chainlink-common to d3ec3d0d. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pins chainlink-common#2472 so the resource_manager_utilization gauge no longer gains a series per execution. On staging zone-a that growth pushed the OTLP export past the 16 MiB collector limit and dropped every engine metric. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…on 463eb552 Resolves go.mod/go.sum conflicts by taking develop and re-pinning common to the chainlink-common#2472 branch head (utilization gauge cardinality fix). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Matches the gas meter in LOOP plugins, which uses the server's DurableEmitter. If none is configured the engine logs once and emits nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|





What
When
[Metering].MeterRecordsEnabledis on, the syncer passes the metering identity to every v2 engine, and each engine owns itsResourceManager. After each executionbaseEngine.emitComputeUsageemits oneMETER_ACTION_USAGErecord:cre:workflow:compute, value in msResourceId<workflow_id>:<execution_id>EventIdcre:workflow:<wf>:<exec>:<exec>)Identity.Service/Don.DonIdworkflow-engine/ local node's workflow DONIdentity.ResourcePool/ResourcePoolIdcre:workflow:compute/cre:workflow:computeOrgIdTesting
Verified on Staging compute + gas records are emitted and accepted by ChIP.