Propagate correlation ID from Geo secondary to primary site
What does this MR do and why?
This MR adds correlation ID propagation to Geo requests from secondary to primary sites. When a request originates on a Geo secondary (e.g., git clone via HTTP, web UI requests), the same correlation ID is now forwarded to the primary site, enabling end-to-end request tracing across Geo sites.
Changes
- Workhorse: Added
WithCorrelationID()proxy option that forwards the correlation ID viaX-Request-IDheader when proxying requests to the primary. - Rails
BaseRequest: AddedX-Request-IDheader to Geo request headers, ensuring allGeo::RequestServicerequests include the correlation ID. - Rails
git_http_controller: Updated to read correlation ID from incomingX-Request-IDheader for Geo-proxied requests.
Why
Currently, when troubleshooting issues on Geo setups, it's difficult to correlate logs between secondary and primary sites because each site generates its own correlation ID. This change enables operators to trace a single request across both sites using the same correlation ID.
References
Related to #513034 (closed)
Example
Note that the correlation ID set remains the same throughout the sites.
# Fetch the secondary with a custom Request-ID
curl -v -H "X-Request-ID: my-custom-corr-id-789" "http://127.0.0.1:3001/root/test"
# Check secondary for custom correlation ID
echo "=== Secondary Workhorse ===" && grep "my-custom-corr-id-789" ~/code/gdk2/log/gitlab-workhorse/current 2>/dev/null | tail -3
=== Secondary Workhorse ===
2026-01-22_18:37:42.39960 gitlab-workhorse : {"backend_id":"geo_primary_site","body_limit":104857600,"content_type":"text/html;
charset=utf-8","correlation_id":"my-custom-corr-id-789","duration_ms":27,"host":"127.0.0.1:3001","level":"info","method":"GET","msg":
"access","proto":"HTTP/1.1","read_bytes":123,"referrer":"","remote_addr":"127.0.0.1:60887","remote_ip":"127.0.0.1","route":"",
"route_id":"proxy","status":302,"system":"http","time":"2026-01-22T13:37:42-05:00","ttfb_ms":27,"uri":"/root/test","user_agent":"curl/
8.7.1","written_bytes":101}
# Check primary for custom correlation ID
echo "=== Primary Workhorse ===" && grep "my-custom-corr-id-789" ~/code/gdk1/log/gitlab-workhorse/current 2>/dev/null | tail -3
=== Primary Workhorse ===
2026-01-22_18:37:42.39865 gitlab-workhorse : {"backend_id":"rails","body_limit":104857600,"content_type":"text/html;
charset=utf-8","correlation_id":"my-custom-corr-id-789","duration_ms":25,"host":"127.0.0.1:3333","level":"info","method":"GET","msg":
"access","proto":"HTTP/1.1","read_bytes":716,"referrer":"","remote_addr":"127.0.0.1:60877","remote_ip":"127.0.0.1","route":"",
"route_id":"default","status":302,"system":"http","time":"2026-01-22T13:37:42-05:00","ttfb_ms":25,"uri":"/root/test","user_agent":
"curl/8.7.1","written_bytes":101}
# Check primary Rails logs
echo "=== Primary Rails ===" && grep "my-custom-corr-id-789" ~/code/gdk1/gitlab/log/*.log 2>/dev/null | head -3
=== Primary Rails ===
{"method":"GET","path":"/root/test","format":"*/*","controller":"ProjectsController","action":"show","status":302,"location":"http://127.0.0.1:3000/users/sign_in","time":"2026-01-22T18:37:42.397Z",
"params":[{"key":"namespace_id","value":"root"},{"key":"id","value":"test"}],"correlation_id":"my-custom-corr-id-789","meta.
caller_id":"ProjectsController#show","meta.feature_category":"groups_and_projects","meta.organization_id":1,"meta.remote_ip":"127.0.0.
1","meta.http_router_rule_action":"proxy","meta.client_id":"ip/127.0.0.1","remote_ip":"127.0.0.1","ua":"curl/8.7.1",
How to set up and validate locally
The primary site's Workhorse must be configured to accept incoming correlation IDs. This requires the -propagateCorrelationID flag.
For GDK (manual workaround - gets reset on gdk reconfigure):
# On the primary GDK
sv stop primary_gdk/services/gitlab-workhorse sed -i '' 's/-apiCiLongPollingDuration "0s"$/-apiCiLongPollingDuration "0s" -propagateCorrelationID/' primary_gdkservices/gitlab-workhorse/run sv start primary_gdk/services/gitlab-workhorse
For Omnibus (production):
# In /etc/gitlab/gitlab.rb on the primary
gitlab_workhorse['propagate_correlation_id'] = true
gitlab_workhorse['trusted_cidrs_for_propagation'] = %w(<secondary-site-ip>/32)
Then run gitlab-ctl reconfigure.
For Helm charts:
gitlab:
webservice:
workhorse:
extraArgs: "-propagateCorrelationID"
trustedCIDRsForPropagation: ["<secondary-site-ip>/32"]
Validation steps
- Rebuild Workhorse on the secondary:
cd gitlab/workhorse && make gdk restart gitlab-workhorse - Perform a git clone from the secondary:
git clonehttp://127.0.0.1:3001/root/test.git - Check the secondary Workhorse logs for the correlation ID:
tail -10 ~gitlab-workhorse/current | grep "info_refs"Note thecorrelation_idvalue (e.g.,01KFED3JBW2MJERK4HEEHWDD79) - Verify the same correlation ID appears on the primary:
grep "01KFED3JBW2MJERK4HEEHWDD79" ~log/gitlab-workhorse/current - For web UI requests, navigate to a project page on the secondary (e.g., http://127.0.0.1:3001/root/test) and verify matching correlation IDs in:
- Secondary Workhorse:
log/gitlab-workhorse/current - Primary Workhorse:
log/gitlab-workhorse/current - Primary Rails:
log/graphql_json.log
- Secondary Workhorse:
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.