Skip to content

Implement Idempotency-keys for webhooks

  • Please check this box if this contribution uses AI-generated content (including content generated by GitLab Duo features) as outlined in the GitLab DCO & CLA

What does this MR do and why?

This Merge Request implements support for idempotency keys in web hook requests, as proposed in #388692 (closed). The implementation will allow for safer automatic retries and bulk retries of web hook events by enabling clients to detect events they have already processed.

Key changes and implementation details:

  1. Added idempotency_key generation and handling in WebHookService, with the ability to use an existing key or generate a new UUID.
  2. Updated the WebHookLog database schema to store idempotency_key uuid.
  3. Modified HookLogActions to pass the existing idempotency_key from the WebHookLog that is being retried to WebHook#execute.
  4. Modified WebHook and WebHookWorker to propagate idempotency_key throughout the execution process.
  5. Implemented the new 'Idempotency-Key' header in WebHookService webhook requests.
  6. Modified LogExecutionService to pull 'Idempotency-Key' from the request headers and store it in the idempotency-key columns of WebHookLog.
  7. Updated documentation to reflect the new idempotency key feature.
  8. Added test coverage for all touch points in the idempotency key functionality.

update: after some more discussion, we decided that idempotency_key did not need it's own column in WebHookLog and could instead be stored in the existing request_headers hash.

Screenshots or screen recordings

The main use case to test is retrying a webhook that receives an error response (500 in this case). Retries in master will return existing headers that are unique to each webhook request. Retries in this feature branch will return the new 'Idempotency-key' header that is consitent across retries.

tarampampam/webhook-tester in a convenient docker image is used to test webhooks locally (details in "How to set up and validate locally").

Master Feature Branch
webhook-master webhook-feature-branch

How to set up and validate locally

setup-guide

  1. In order to test local webhooks, you will have to have allow_local_requests_from_web_hooks_and_services set to true in the Application Settings. This can be accomplished in the rails console:
gdk rails c
s = ApplicationSetting.first
s.allow_local_requests_from_web_hooks_and_services = true
s.save!
  1. Local webhooks can be tested with the tarampampam/webhook-tester package. This package has a handy docker image that can serve the app with minimal setup by running:
docker run --rm -p 8080:8080/tcp tarampampam/webhook-tester serve
  1. Open localhost:8080 in a tab to see the webhook-tester UI - you will want to keep this tab open.
  2. Copy the url that is generated by webhook-tester.
  3. Create a new webhook in a personal project (Project Show Sidebar -> Settings -> Webhooks)
  4. Use the copied URL from step 3 to fill out the "URL" field in the webhook settings. You can optionally append a /500 path to the url, which will result in webhook-tester responding with 500 errors for this endpoint.
  5. In the webhook form, check some operations in the you can generate events for. It's important to test with events rather than just using the "Test" feature of the webhook settings alone, because generating the real events utilizes a background job with WebHookWorker where "Test" runs synchronously.
  6. Click "Test" to fire a webhook, and go to the webhook-tester UI to verify the webhook was received.
  7. Generate one of the events you selected in the webhook edit panel (for my above examples, this was changing a wiki article)
  8. Go to the webhook-tester UI to see this event captured. If you are testing on the feature branch, note the Idempotency-Key value.
  9. Go back to the edit settings page of your webhook in the Gitlab tab. This is under Settings->Webhook->"Edit" for the target webhook.
  10. Scroll to the bottom of this page to find the webhook log. Click "view details" on the most recent webhook after ensuring the "Request Time" matches the webhook just sent.
  11. Click the "Resend Request" button on this page
  12. Go back to the webhook-tester UI. If you are on the feature branch, you should observe the latest request has an Idempotency-key value that is identical to the original request.

Once this is setup on master or this feature branch, you may switch branches and start at step #9 (closed) to test the flow again with your selected branch.

Edited by Van Anderson

Merge request reports

Loading