Skip to content

Require a temporal-resource-id annotation or exemption on every RPC - #897

Merged
jiechenz merged 2 commits into
jiechenz/standalone-resource-idfrom
jiechenz/enforce-resource-id
Oct 27, 2026
Merged

jiechenz merged 2 commits into
jiechenz/standalone-resource-idfrom
jiechenz/enforce-resource-id

Conversation

@jiechenz

@jiechenz jiechenz commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #877.

What changed?

  • Add protoc-gen-resource-id-lint, a protoc plugin that make runs in the grpc lint step (so CI runs it too). It checks every RPC in every service and fails when:
    • the RPC has neither a temporal-resource-id request_header annotation nor an entry in cmd/protoc-gen-resource-id-lint/exemptions.go;
    • an exempted RPC has the annotation;
    • an exemption names an RPC that does not exist.
  • Exempt the RPCs that have no single resource to route by: namespace and cluster management, list/count queries, workflow rules, ShutdownWorker, deprecated deployment APIs, and all OperatorService RPCs.
  • Add temporal-resource-id annotations to RPCs that were missing them, using the same values as their sibling RPCs:
    • CreateWorkerDeployment: deployment:{deployment_name}
    • CreateWorkerDeploymentVersion, UpdateWorkerDeploymentVersionComputeConfig, ValidateWorkerDeploymentVersionComputeConfig: deployment:{deployment_version.deployment_name}
    • UpdateWorkerVersioningRules, GetWorkerVersioningRules, UpdateWorkerBuildIdCompatibility, GetWorkerBuildIdCompatibility: taskqueue:{task_queue}

The check only requires that the annotation is present. It does not validate the annotation value.

To exempt a new RPC, add "<Service>.<Method>": {} to exemptions.go.

Why?

New RPCs have shipped without a temporal-resource-id annotation, for example the standalone Nexus operation RPCs fixed in #877. Requiring the annotation, or an explicit exemption, makes that decision part of every API review.

Breaking changes

None at the wire or code level. The eight new annotations change the request headers SDKs send for those RPCs once they pick up the new protos.

Server PR

None required. After the api-go bump, regenerate common/rpc/interceptor/routing_key_extractor_gen.go (make proto-codegen) to pick up the eight new annotations.

@jiechenz
jiechenz requested review from a team as code owners October 27, 2026 01:04
@jiechenz
jiechenz added this pull request to stack #898 October 27, 2026 01:06
Add protoc-gen-resource-id-lint, run by `make` as part of the grpc
lint step. It fails when an RPC has neither a temporal-resource-id
request_header annotation nor an entry in
cmd/protoc-gen-resource-id-lint/exemptions.go, when an exempted RPC
has the annotation, or when an exemption names an RPC that does not
exist.

Exempt the RPCs that have no single resource to route by, and annotate
the worker deployment and task queue RPCs that were missing it, using
the same values as their sibling RPCs.
@jiechenz
jiechenz force-pushed the jiechenz/enforce-resource-id branch from 0e0f781 to ce9db57 Compare October 27, 2026 01:08
@jiechenz
jiechenz requested a review from yycptt October 27, 2026 01:17
@@ -0,0 +1,5 @@
module github.com/temporalio/api/cmd/protoc-gen-resource-id-lint

go 1.25.4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be 1.25?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed but I used 1.25.4 to match the other two plugins in cmd/.

@yuandrew yuandrew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say a test validating the test successfully rejects a missing annotation would be good, but looks like none of our other cmd/ tools have one.. 🤷

Cover an RPC with neither the annotation nor an exemption, an
annotation for a different header, an exempted RPC that has the
annotation, and an exemption for an RPC that does not exist, plus a
passing service. Run the test before installing the plugin, so `make`
and CI run it.
@jiechenz

Copy link
Copy Markdown
Contributor Author

I'd say a test validating the test successfully rejects a missing annotation would be good, but looks like none of our other cmd/ tools have one.. 🤷

Added a test

@jiechenz
jiechenz merged commit 3c0912a into main Oct 27, 2026
4 checks passed
@jiechenz
jiechenz deleted the jiechenz/enforce-resource-id branch October 27, 2026 23:53
jiechenz added a commit to temporalio/temporal that referenced this pull request Oct 28, 2026
## What changed?
- Bump `go.temporal.io/api` to `v1.64.1-0.20261027235544-fa71e29e58da`
(root and `tests/mixedbrain`) to pick up the `temporal-resource-id`
annotations from temporalio/api#877 and temporalio/api#897.
- Regenerate `common/rpc/interceptor/routing_key_extractor_gen.go`. 15
RPCs gain a routing key:
- by `operation_id`: `StartNexusOperationExecution`,
`DescribeNexusOperationExecution`, `PollNexusOperationExecution`,
`RequestCancelNexusOperationExecution`,
`TerminateNexusOperationExecution`, `DeleteNexusOperationExecution`
  - by `activity_id`: `DeleteActivityExecution`
- by deployment name: `CreateWorkerDeployment`,
`CreateWorkerDeploymentVersion`,
`UpdateWorkerDeploymentVersionComputeConfig`,
`ValidateWorkerDeploymentVersionComputeConfig`
- by task queue: `UpdateWorkerVersioningRules`,
`GetWorkerVersioningRules`, `UpdateWorkerBuildIdCompatibility`,
`GetWorkerBuildIdCompatibility`
- Add the 15 RPCs to `TestRoutingKeyInterceptor_AllMethods`.

## Why?
Make sure Nexus operations have routingKey associated.

## How did you test it?
- [x] built
- [ ] run locally and tested manually
- [x] covered by existing tests
- [x] added new unit test(s)
- [ ] added new functional test(s)

<details><summary>go test -tags test_dep -count=1
./common/rpc/interceptor/...</summary>

```
ok      go.temporal.io/server/common/rpc/interceptor    4.919s
ok      go.temporal.io/server/common/rpc/interceptor/logtags    0.929s
```
</details>

<details><summary>Same test with routing_key_extractor_gen.go from
main</summary>

```
--- FAIL: TestRoutingKeyInterceptor_AllMethods
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/ValidateWorkerDeploymentVersionComputeConfig
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/UpdateWorkerVersioningRules
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/UpdateWorkerDeploymentVersionComputeConfig
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/UpdateWorkerBuildIdCompatibility
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/TerminateNexusOperationExecution
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/StartNexusOperationExecution
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/RequestCancelNexusOperationExecution
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/PollNexusOperationExecution
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/GetWorkerVersioningRules
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/GetWorkerBuildIdCompatibility
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/DescribeNexusOperationExecution
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/DeleteNexusOperationExecution
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/DeleteActivityExecution
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/CreateWorkerDeploymentVersion
    --- FAIL: TestRoutingKeyInterceptor_AllMethods/CreateWorkerDeployment
```
</details>

<details><summary>make lint-code GOLANGCI_LINT_BASE_REV=origin/main
LINT_CODE_TARGETS=./common/rpc/interceptor/...</summary>

```
0 issues.
```
</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants