Skip to content

fix(sdk): regenerate service.instance.id post-fork in MeterProvider and TracerProvider#5000

Closed
sterchelen wants to merge 3 commits into
open-telemetry:mainfrom
sterchelen:fix/post-fork-service-instance-id
Closed

fix(sdk): regenerate service.instance.id post-fork in MeterProvider and TracerProvider#5000
sterchelen wants to merge 3 commits into
open-telemetry:mainfrom
sterchelen:fix/post-fork-service-instance-id

Conversation

@sterchelen

Copy link
Copy Markdown

Description

When a prefork server (e.g. gunicorn) forks workers, all workers inherit the same Resource from the master process — including the same service.instance.id. The SDK already restarts background threads post-fork (PeriodicExportingMetricReader, BatchSpanProcessor) but never updates the resource identity. This causes metric and trace collisions in OTLP backends where multiple workers exporting with the same resource identity result in incorrect aggregation (last-write-wins) instead of correct summation.

This PR registers an os.register_at_fork(after_in_child=...) hook on both MeterProvider and TracerProvider that replaces service.instance.id with a fresh UUID in each forked worker. All other resource attributes are preserved via Resource.merge(). WeakMethod is used for the hook reference, consistent with the existing pattern in PeriodicExportingMetricReader and BatchSpanProcessor.

Fixes #4390
Related: #3885

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Two new test files covering both providers:

  • tests/metrics/test_meter_provider_fork.py
  • tests/trace/test_tracer_provider_fork.py

Each covers:
_at_fork_reinit assigns a new service.instance.id
Other resource attributes are preserved

A real fork() produces a distinct ID in the child vs the parent
4 concurrent forks each produce a unique ID

Run with:
pytest opentelemetry-sdk/tests/metrics/test_meter_provider_fork.py
pytest opentelemetry-sdk/tests/trace/test_tracer_provider_fork.py

  • Unit tests (fork-based, *nix only)

Does This PR Require a Contrib Repo Change?

  • Yes. - Link to PR:
  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

This hook runs post-fork in each worker and replaces service.instance.id
with a fresh UUID, ensuring each worker is a distinct instance.
"""
self._sdk_config.resource = self._sdk_config.resource.merge(

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.

We are not setting this in the resource attributes, also not sure the issue is metrics specific.

@sterchelen sterchelen Mar 20, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

We are not setting this in the resource attributes

Not sure to get your point but if the user didn't set it, workers would be completely indistinguishable in the backend after fork, which is worse than having no ID at all. By always generating one post-fork we ensure every worker has a distinct identity regardless of whether the user configured it upfront.

On the second point: agreed, the problem affects both metrics and traces 👍🏼

@xrmx xrmx Mar 23, 2026

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.

My point is that if we have a solution that work fine after forks() since the semantic conventions is now stable we can add this to the default resource detector. This way we have the very same attributes before and after fork.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@xrmx just pushed changes with two distinct commits,

  1. 4b7334a to auto-generate service.instance.id
  2. 3256bf0 to fix post-fork issue

changelog has been changed as well 👍🏼

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@xrmx tell me if I need to do something :)

@sterchelen sterchelen force-pushed the fix/post-fork-service-instance-id branch 2 times, most recently from 63676db to 70b6fff Compare March 23, 2026 08:02
@xrmx xrmx moved this to Reviewed PRs that need fixes in Python PR digest Mar 23, 2026
The Python SDK did not auto-generate service.instance.id, unlike the
Java SDK and the stable semantic convention recommendation. Add it to
_DEFAULT_RESOURCE so every process gets a unique instance identity at
startup without any user configuration.
…nd TracerProvider

When a prefork server (e.g. gunicorn) forks workers, all workers inherit
the same Resource from the master process, including the same
service.instance.id. Register an os.register_at_fork(after_in_child=...)
hook on both MeterProvider and TracerProvider that replaces
service.instance.id with a fresh UUID in each forked worker, ensuring
distinct resource identities without any user configuration.

Resource.merge() preserves all other resource attributes. WeakMethod is
used for the hook reference, consistent with the existing pattern in
PeriodicExportingMetricReader and BatchSpanProcessor.

Fixes: open-telemetry#4390
Related: open-telemetry#3885
@sterchelen sterchelen force-pushed the fix/post-fork-service-instance-id branch from 70b6fff to 3256bf0 Compare March 24, 2026 12:30
@sterchelen sterchelen requested a review from xrmx March 25, 2026 17:09
@github-actions

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment.
If you're still working on this, please add a comment or push new commits.

@github-actions github-actions Bot added the Stale label Apr 17, 2026
@sterchelen

Copy link
Copy Markdown
Author

It will be closed if no further activity occurs within 14 days of this comment.

No I am still waiting for review :)

@github-actions github-actions Bot removed the Stale label Apr 23, 2026

@emdneto emdneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@sterchelen Thanks for the PR and sorry for the late review on this. I was dealing with that issue recently and just saw your PR today

I believe we need a single shared fork hook and a provider registry so the child process generates one UUID, and you iterate over the providers set in the registry and apply the new UUID to all registered providers within the forked process.

My understanding is that a provider created after the fork should also get the same child UUID when it is created.

with a fresh UUID, ensuring each worker is a distinct instance.
"""
self._sdk_config.resource = self._sdk_config.resource.merge(
Resource({"service.instance.id": str(uuid4())})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will generate a unique id for metrics and another id for traces. My understanding is that this id should be the same for both providers, but still unique at the instance level.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You are right (and sorry for my late answer... dealing with a complex migration).
I'll do that.

@github-actions

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment.
If you're still working on this, please add a comment or push new commits.

@github-actions github-actions Bot added the Stale label May 19, 2026
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

This PR has been closed due to inactivity. Please reopen if you would like to continue working on it.

@github-actions github-actions Bot closed this Jun 2, 2026
@github-project-automation github-project-automation Bot moved this from Reviewed PRs that need fixes to Done in Python PR digest Jun 2, 2026
@sterchelen

Copy link
Copy Markdown
Author

I can't reopen my PR ...

Address review on open-telemetry#5000: the per-provider fork hook generated a separate
uuid4() for MeterProvider and TracerProvider, so after a fork metrics and
traces in the same worker reported different service.instance.id values.

Introduce a shared registry and a single os.register_at_fork hook in
opentelemetry.sdk._shared_internal._fork. The child generates one UUID and
applies it to every registered provider; providers created after the fork
adopt the same id at construction via register_provider(). A threading.Lock
guards the registry (thread-safe registration, free-threading ready) and is
acquired in the before hook / released in after_in_parent/after_in_child to
stay fork-safe.

Providers now expose _reset_service_instance_id() instead of _at_fork_reinit().

Fixes: open-telemetry#4390
Related: open-telemetry#3885
@sterchelen

Copy link
Copy Markdown
Author

@emdneto, could you reopen the PR for me please? I pushed the change you requested 🙏🏼
Thx 🙇🏼

@emdneto emdneto reopened this Jun 9, 2026
@emdneto

emdneto commented Jun 9, 2026

Copy link
Copy Markdown
Member

@sterchelen just reopened the thread. Will take a look at your changes. Thanks

@sterchelen

Copy link
Copy Markdown
Author

@emdneto thx ; I answered in the conversation you shared to this PR 👍🏼

@github-actions

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment.
If you're still working on this, please add a comment or push new commits.

@github-actions github-actions Bot added the Stale label Jun 26, 2026
@emdneto

emdneto commented Jul 2, 2026

Copy link
Copy Markdown
Member

Hey @sterchelen I think #5280 will supersede this PR once merged.

@github-actions github-actions Bot removed the Stale label Jul 3, 2026
@xrmx

xrmx commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Closing in favor of #5280

@xrmx xrmx closed this Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Auto-instrumentation] Add unique instance.id to all post-fork processes

3 participants