From 139cfe66bdcc460c32be065d4eb262713b594626 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 18 Dec 2024 13:08:22 -0800 Subject: [PATCH 1/9] [nexus] start DB model for webhooks --- schema/crdb/add-webhooks/README.adoc | 40 ++++++++ schema/crdb/add-webhooks/up01.sql | 10 ++ schema/crdb/add-webhooks/up02.sql | 13 +++ schema/crdb/add-webhooks/up03.sql | 5 + schema/crdb/add-webhooks/up04.sql | 10 ++ schema/crdb/add-webhooks/up05.sql | 4 + schema/crdb/add-webhooks/up06.sql | 12 +++ schema/crdb/add-webhooks/up07.sql | 5 + schema/crdb/add-webhooks/up08.sql | 7 ++ schema/crdb/add-webhooks/up09.sql | 9 ++ schema/crdb/add-webhooks/up10.sql | 27 ++++++ schema/crdb/add-webhooks/up11.sql | 4 + schema/crdb/dbinit.sql | 131 +++++++++++++++++++++++++++ 13 files changed, 277 insertions(+) create mode 100644 schema/crdb/add-webhooks/README.adoc create mode 100644 schema/crdb/add-webhooks/up01.sql create mode 100644 schema/crdb/add-webhooks/up02.sql create mode 100644 schema/crdb/add-webhooks/up03.sql create mode 100644 schema/crdb/add-webhooks/up04.sql create mode 100644 schema/crdb/add-webhooks/up05.sql create mode 100644 schema/crdb/add-webhooks/up06.sql create mode 100644 schema/crdb/add-webhooks/up07.sql create mode 100644 schema/crdb/add-webhooks/up08.sql create mode 100644 schema/crdb/add-webhooks/up09.sql create mode 100644 schema/crdb/add-webhooks/up10.sql create mode 100644 schema/crdb/add-webhooks/up11.sql diff --git a/schema/crdb/add-webhooks/README.adoc b/schema/crdb/add-webhooks/README.adoc new file mode 100644 index 0000000000..f3ea209b55 --- /dev/null +++ b/schema/crdb/add-webhooks/README.adoc @@ -0,0 +1,40 @@ +# Overview + +This migration adds initial tables required for webhook delivery. + +## Upgrade steps + +The individual transactions in this upgrade do the following: + +* *Webhook receivers*: +** `up01.sql` creates the `omicron.public.webhook_rx` table, which stores +the receiver endpoints that receive webhook events. +** *Receiver secrets*: +*** `up02.sql` creates the `omicron.public.webhook_rx_secret` table, which +associates webhook receivers with secret keys and their IDs. +*** `up03.sql` creates the `lookup_webhook_secrets_by_rx` index on that table, +for looking up all secrets associated with a receiver. +** *Receiver subscriptions*: +*** `up04.sql` creates the `omicron.public.webhook_rx_subscription` table, which +associates a webhook receiver with multiple event classes that the receiver is +subscribed to. +*** `up05.sql` creates an index `lookup_webhook_subscriptions_by_rx` for +looking up all event classes that a receiver ID is subscribed to. +* *Webhook message dispatching and delivery attempts*: +** *Dispatch table*: +*** `up06.sql` creates the table `omicron.public.webhook_msg_dispatch`, which +tracks the webhook messages that have been dispatched to receivers. +*** `up07.sql` creates an index `lookup_webhook_dispatched_to_rx` for looking up +entries in `omicron.public.webhook_msg_dispatch` by receiver ID. +*** `up08.sql` creates an index `webhook_dispatch_in_flight` for looking up all currently in-flight webhook +messages (entries in `omicron.public.webhook_msg_dispatch` where the +`time_completed` field has not been set). +** *Delivery attempts*: +*** `up09.sql` creates the enum `omicron.public.webhook_msg_delivery_result`, +representing the potential outcomes of a webhook delivery attempt. +*** `up10.sql` creates the table `omicron.public.webhook_msg_delivery_attempt`, +which records each individual delivery attempt for a webhook message in the +`webhook_msg_dispatch` table. +*** `up11.sql` creates an index `lookup_webhook_delivery_attempts_for_msg` on +`omicron.public.webhook_msg_delivery_attempt`, for looking up all attempts to +deliver a message with a given dispatch ID. diff --git a/schema/crdb/add-webhooks/up01.sql b/schema/crdb/add-webhooks/up01.sql new file mode 100644 index 0000000000..58799496b0 --- /dev/null +++ b/schema/crdb/add-webhooks/up01.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS omicron.public.webhook_rx ( + id UUID PRIMARY KEY, + -- A human-readable identifier for this webhook receiver. + name STRING(63) NOT NULL, + -- URL of the endpoint webhooks are delivered to. + endpoint STRING(512) NOT NULL, + -- TODO(eliza): how do we track which roles are assigned to a webhook? + time_created TIMESTAMPTZ NOT NULL, + time_deleted TIMESTAMPTZ +); diff --git a/schema/crdb/add-webhooks/up02.sql b/schema/crdb/add-webhooks/up02.sql new file mode 100644 index 0000000000..df945f4299 --- /dev/null +++ b/schema/crdb/add-webhooks/up02.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS omicron.public.webhook_rx_secret ( + -- UUID of the webhook receiver (foreign key into + -- `omicron.public.webhook_rx`) + rx_id UUID NOT NULL, + -- ID of this secret. + signature_id STRING(63) NOT NULL, + -- Secret value. + secret BYTES NOT NULL, + time_created TIMESTAMPTZ NOT NULL, + time_deleted TIMESTAMPTZ, + + PRIMARY KEY (signature_id, rx_id) +); diff --git a/schema/crdb/add-webhooks/up03.sql b/schema/crdb/add-webhooks/up03.sql new file mode 100644 index 0000000000..5a79908857 --- /dev/null +++ b/schema/crdb/add-webhooks/up03.sql @@ -0,0 +1,5 @@ +CREATE INDEX IF NOT EXISTS lookup_webhook_secrets_by_rx +ON omicron.public.webhook_rx_secret ( + rx_id +) WHERE + time_deleted IS NULL; diff --git a/schema/crdb/add-webhooks/up04.sql b/schema/crdb/add-webhooks/up04.sql new file mode 100644 index 0000000000..7911418a78 --- /dev/null +++ b/schema/crdb/add-webhooks/up04.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS omicron.public.webhook_rx_subscription ( + -- UUID of the webhook receiver (foreign key into + -- `omicron.public.webhook_rx`) + rx_id UUID NOT NULL, + -- An event class to which this receiver is subscribed. + event_class STRING(512) NOT NULL, + time_created TIMESTAMPTZ NOT NULL, + + PRIMARY KEY (rx_id, event_class) +); diff --git a/schema/crdb/add-webhooks/up05.sql b/schema/crdb/add-webhooks/up05.sql new file mode 100644 index 0000000000..4ffe7cbce0 --- /dev/null +++ b/schema/crdb/add-webhooks/up05.sql @@ -0,0 +1,4 @@ +CREATE INDEX IF NOT EXISTS lookup_webhook_subscriptions_by_rx +ON omicron.public.webhook_rx_subscription ( + rx_id +); diff --git a/schema/crdb/add-webhooks/up06.sql b/schema/crdb/add-webhooks/up06.sql new file mode 100644 index 0000000000..08a44f54e3 --- /dev/null +++ b/schema/crdb/add-webhooks/up06.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_dispatch ( + -- UUID of this dispatch. + id UUID PRIMARY KEY, + -- UUID of the webhook receiver (foreign key into + -- `omicron.public.webhook_rx`) + rx_id UUID NOT NULL, + payload JSONB NOT NULL, + time_created TIMESTAMPTZ NOT NULL, + -- If this is set, then this webhook message has either been delivered + -- successfully, or is considered permanently failed. + time_completed TIMESTAMPTZ, +); diff --git a/schema/crdb/add-webhooks/up07.sql b/schema/crdb/add-webhooks/up07.sql new file mode 100644 index 0000000000..4cc13a67cc --- /dev/null +++ b/schema/crdb/add-webhooks/up07.sql @@ -0,0 +1,5 @@ +-- Index for looking up all webhook messages dispatched to a receiver ID +CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx +ON omicron.public.webhook_msg_dispatch ( + rx_id +); diff --git a/schema/crdb/add-webhooks/up08.sql b/schema/crdb/add-webhooks/up08.sql new file mode 100644 index 0000000000..d7cb44b173 --- /dev/null +++ b/schema/crdb/add-webhooks/up08.sql @@ -0,0 +1,7 @@ +-- Index for looking up all currently in-flight webhook messages, and ordering +-- them by their creation times. +CREATE INDEX IF NOT EXISTS webhook_dispatch_in_flight +ON omicron.public.webhook_msg_dispatch ( + time_created, id +) WHERE + time_completed IS NULL; diff --git a/schema/crdb/add-webhooks/up09.sql b/schema/crdb/add-webhooks/up09.sql new file mode 100644 index 0000000000..00e5cb3e7b --- /dev/null +++ b/schema/crdb/add-webhooks/up09.sql @@ -0,0 +1,9 @@ +CREATE TYPE IF NOT EXISTS omicron.public.webhook_msg_delivery_result as ENUM ( + -- The delivery attempt failed with an HTTP error. + 'failed_http_error', + -- The delivery attempt failed because the receiver endpoint was + -- unreachable. + 'failed_unreachable', + -- The delivery attempt succeeded. + 'succeeded' +); diff --git a/schema/crdb/add-webhooks/up10.sql b/schema/crdb/add-webhooks/up10.sql new file mode 100644 index 0000000000..19f87bf459 --- /dev/null +++ b/schema/crdb/add-webhooks/up10.sql @@ -0,0 +1,27 @@ +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_delivery_attempt ( + id UUID PRIMARY KEY, + -- Foreign key into `omicron.public.webhook_msg_dispatch`. + dispatch_id UUID NOT NULL, + result omicron.public.webhook_msg_delivery_result NOT NULL, + response_status INT2, + response_duration INTERVAL, + time_created TIMESTAMPTZ NOT NULL, + + CONSTRAINT response_iff_not_unreachable CHECK ( + ( + -- If the result is 'succeedeed' or 'failed_http_error', response + -- data must be present. + (result = 'succeeded' OR result = 'failed_http_error') AND ( + response_status IS NOT NULL AND + response_duration IS NOT NULL + ) + ) OR ( + -- If the result is 'failed_unreachable', no response data is + -- present. + (result = 'failed_unreachable') AND ( + response_status IS NULL AND + response_duration IS NULL + ) + ) + ) +); diff --git a/schema/crdb/add-webhooks/up11.sql b/schema/crdb/add-webhooks/up11.sql new file mode 100644 index 0000000000..2a32f10969 --- /dev/null +++ b/schema/crdb/add-webhooks/up11.sql @@ -0,0 +1,4 @@ +CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg +ON omicron.public.webhook_msg_delivery_attempts ( + dispatch_id +); diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index 75b7dbaf08..a3577848e4 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4683,6 +4683,137 @@ CREATE UNIQUE INDEX IF NOT EXISTS one_record_per_volume_resource_usage on omicro region_snapshot_snapshot_id ); +/* + * WEBHOOKS + */ + + +/* + * Webhook receivers, receiver secrets, and receiver subscriptions. + */ + +CREATE TABLE IF NOT EXISTS omicron.public.webhook_rx ( + id UUID PRIMARY KEY, + -- A human-readable identifier for this webhook receiver. + name STRING(63) NOT NULL, + -- URL of the endpoint webhooks are delivered to. + endpoint STRING(512) NOT NULL, + -- TODO(eliza): how do we track which roles are assigned to a webhook? + time_created TIMESTAMPTZ NOT NULL, + time_modified TIMESTAMPTZ, + time_deleted TIMESTAMPTZ +); + +CREATE TABLE IF NOT EXISTS omicron.public.webhook_rx_secret ( + -- UUID of the webhook receiver (foreign key into + -- `omicron.public.webhook_rx`) + rx_id UUID NOT NULL, + -- ID of this secret. + signature_id STRING(63) NOT NULL, + -- Secret value. + secret BYTES NOT NULL, + time_created TIMESTAMPTZ NOT NULL, + time_deleted TIMESTAMPTZ, + + PRIMARY KEY (signature_id, rx_id) +); + +CREATE INDEX IF NOT EXISTS lookup_webhook_secrets_by_rx +ON omicron.public.webhook_rx_secret ( + rx_id +) WHERE + time_deleted IS NULL; + +CREATE TABLE IF NOT EXISTS omicron.public.webhook_subscription ( + -- UUID of the webhook receiver (foreign key into + -- `omicron.public.webhook_rx`) + rx_id UUID NOT NULL, + -- An event class to which this receiver is subscribed. + event_class STRING(512) NOT NULL, + time_created TIMESTAMPTZ NOT NULL, + + PRIMARY KEY (rx_id, event_class) +); + +CREATE INDEX IF NOT EXISTS lookup_webhook_subscriptions_by_rx +ON omicron.public.webhook_rx_subscription ( + rx_id +); + +/* + * Webhook message dispatching and delivery attempts. + */ + +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_dispatch ( + -- UUID of this dispatch. + id UUID PRIMARY KEY, + -- UUID of the webhook receiver (foreign key into + -- `omicron.public.webhook_rx`) + rx_id UUID NOT NULL, + payload JSONB NOT NULL, + time_created TIMESTAMPTZ NOT NULL, + -- If this is set, then this webhook message has either been delivered + -- successfully, or is considered permanently failed. + time_completed TIMESTAMPTZ, +); + +-- Index for looking up all webhook messages dispatched to a receiver ID +CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx +ON omicron.public.webhook_msg_dispatch ( + rx_id +); + +-- Index for looking up all currently in-flight webhook messages, and ordering +-- them by their creation times. +CREATE INDEX IF NOT EXISTS webhook_dispatch_in_flight +ON omicron.public.webhook_msg_dispatch ( + time_created, id +) WHERE + time_completed IS NULL; + +CREATE TYPE IF NOT EXISTS omicron.public.webhook_msg_delivery_result as ENUM ( + -- The delivery attempt failed with an HTTP error. + 'failed_http_error', + -- The delivery attempt failed because the receiver endpoint was + -- unreachable. + 'failed_unreachable', + -- The delivery attempt succeeded. + 'succeeded' +); + +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_delivery_attempt ( + id UUID PRIMARY KEY, + -- Foreign key into `omicron.public.webhook_msg_dispatch`. + dispatch_id UUID NOT NULL, + result omicron.public.webhook_msg_delivery_result NOT NULL, + response_status INT2, + response_duration INTERVAL, + time_created TIMESTAMPTZ NOT NULL, + + CONSTRAINT response_iff_not_unreachable CHECK ( + ( + -- If the result is 'succeedeed' or 'failed_http_error', response + -- data must be present. + (result = 'succeeded' OR result = 'failed_http_error') AND ( + response_status IS NOT NULL AND + response_duration IS NOT NULL + ) + ) OR ( + -- If the result is 'failed_unreachable', no response data is + -- present. + (result = 'failed_unreachable') AND ( + response_status IS NULL AND + response_duration IS NULL + ) + ) + ) +); + +CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg +ON omicron.public.webhook_msg_delivery_attempts ( + dispatch_id +); + /* * Keep this at the end of file so that the database does not contain a version * until it is fully populated. From 61c173ed151813988cfda81909e199039d8244eb Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 18 Dec 2024 13:32:15 -0800 Subject: [PATCH 2/9] message queue --- schema/crdb/add-webhooks/README.adoc | 23 ++++++++++++++----- schema/crdb/add-webhooks/up06.sql | 16 +++++--------- schema/crdb/add-webhooks/up07.sql | 13 +++++++---- schema/crdb/add-webhooks/up08.sql | 14 ++++++------ schema/crdb/add-webhooks/up09.sql | 19 +++++++++------- schema/crdb/add-webhooks/up10.sql | 30 ++++--------------------- schema/crdb/add-webhooks/up11.sql | 11 ++++++---- schema/crdb/add-webhooks/up12.sql | 9 ++++++++ schema/crdb/add-webhooks/up13.sql | 27 +++++++++++++++++++++++ schema/crdb/add-webhooks/up14.sql | 4 ++++ schema/crdb/dbinit.sql | 33 +++++++++++++++++++++++++++- 11 files changed, 132 insertions(+), 67 deletions(-) create mode 100644 schema/crdb/add-webhooks/up12.sql create mode 100644 schema/crdb/add-webhooks/up13.sql create mode 100644 schema/crdb/add-webhooks/up14.sql diff --git a/schema/crdb/add-webhooks/README.adoc b/schema/crdb/add-webhooks/README.adoc index f3ea209b55..c913776b73 100644 --- a/schema/crdb/add-webhooks/README.adoc +++ b/schema/crdb/add-webhooks/README.adoc @@ -20,21 +20,32 @@ associates a webhook receiver with multiple event classes that the receiver is subscribed to. *** `up05.sql` creates an index `lookup_webhook_subscriptions_by_rx` for looking up all event classes that a receiver ID is subscribed to. +*** `up06.sql` creates an index `lookup_webhook_rxs_for_event` on +`omicron.public.webhook_rx_subscription` for looking up all receivers subscribed +to a particular event class. +* *Webhook message queue*: +** `up07.sql` creates the `omicron.public.webhook_msg` table, which contains the +queue of un-dispatched webhook events. The dispatcher operates on entries in +this queue, dispatching the event to receivers and generating the payload for +each receiver. +** `up08.sql` creates the `lookup_undispatched_webhook_msgs` index on +`omicron.public.webhook_msg` for looking up webhook messages which have not yet been +dispatched and ordering by their creation times. * *Webhook message dispatching and delivery attempts*: ** *Dispatch table*: -*** `up06.sql` creates the table `omicron.public.webhook_msg_dispatch`, which +*** `up09.sql` creates the table `omicron.public.webhook_msg_dispatch`, which tracks the webhook messages that have been dispatched to receivers. -*** `up07.sql` creates an index `lookup_webhook_dispatched_to_rx` for looking up +*** `up10.sql` creates an index `lookup_webhook_dispatched_to_rx` for looking up entries in `omicron.public.webhook_msg_dispatch` by receiver ID. -*** `up08.sql` creates an index `webhook_dispatch_in_flight` for looking up all currently in-flight webhook +*** `up11.sql` creates an index `webhook_dispatch_in_flight` for looking up all currently in-flight webhook messages (entries in `omicron.public.webhook_msg_dispatch` where the `time_completed` field has not been set). ** *Delivery attempts*: -*** `up09.sql` creates the enum `omicron.public.webhook_msg_delivery_result`, +*** `up12.sql` creates the enum `omicron.public.webhook_msg_delivery_result`, representing the potential outcomes of a webhook delivery attempt. -*** `up10.sql` creates the table `omicron.public.webhook_msg_delivery_attempt`, +*** `up13.sql` creates the table `omicron.public.webhook_msg_delivery_attempt`, which records each individual delivery attempt for a webhook message in the `webhook_msg_dispatch` table. -*** `up11.sql` creates an index `lookup_webhook_delivery_attempts_for_msg` on +*** `up14.sql` creates an index `lookup_webhook_delivery_attempts_for_msg` on `omicron.public.webhook_msg_delivery_attempt`, for looking up all attempts to deliver a message with a given dispatch ID. diff --git a/schema/crdb/add-webhooks/up06.sql b/schema/crdb/add-webhooks/up06.sql index 08a44f54e3..407424440c 100644 --- a/schema/crdb/add-webhooks/up06.sql +++ b/schema/crdb/add-webhooks/up06.sql @@ -1,12 +1,6 @@ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_dispatch ( - -- UUID of this dispatch. - id UUID PRIMARY KEY, - -- UUID of the webhook receiver (foreign key into - -- `omicron.public.webhook_rx`) - rx_id UUID NOT NULL, - payload JSONB NOT NULL, - time_created TIMESTAMPTZ NOT NULL, - -- If this is set, then this webhook message has either been delivered - -- successfully, or is considered permanently failed. - time_completed TIMESTAMPTZ, +-- Look up all webhook receivers subscribed to an event class. This is used by +-- the dispatcher to determine who is interested in a particular event. +CREATE INDEX IF NOT EXISTS lookup_webhook_rxs_for_event +ON omicron.public.webhook_rx_subscription ( + event_class ); diff --git a/schema/crdb/add-webhooks/up07.sql b/schema/crdb/add-webhooks/up07.sql index 4cc13a67cc..ba667e930f 100644 --- a/schema/crdb/add-webhooks/up07.sql +++ b/schema/crdb/add-webhooks/up07.sql @@ -1,5 +1,10 @@ --- Index for looking up all webhook messages dispatched to a receiver ID -CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx -ON omicron.public.webhook_msg_dispatch ( - rx_id +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg ( + id UUID PRIMARY KEY, + time_created TIMESTAMPTZ NOT NULL, + -- Set when dispatch entries have been created for this event. + time_dispatched TIMESTAMPTZ, + -- The class of event that this is. + event_class STRING(512) NOT NULL, + -- Actual event data. The structure of this depends on the event class. + event JSONB NOT NULL ); diff --git a/schema/crdb/add-webhooks/up08.sql b/schema/crdb/add-webhooks/up08.sql index d7cb44b173..e18c2cea1a 100644 --- a/schema/crdb/add-webhooks/up08.sql +++ b/schema/crdb/add-webhooks/up08.sql @@ -1,7 +1,7 @@ --- Index for looking up all currently in-flight webhook messages, and ordering --- them by their creation times. -CREATE INDEX IF NOT EXISTS webhook_dispatch_in_flight -ON omicron.public.webhook_msg_dispatch ( - time_created, id -) WHERE - time_completed IS NULL; +-- Look up webhook messages in need of dispatching. +-- +-- This is used by the message dispatcher when looking for messages to dispatch. +CREATE INDEX IF NOT EXISTS lookup_undispatched_webhook_msgs +ON omicron.public.webhook_msg ( + id, time_created +) WHERE time_dispatched IS NULL; diff --git a/schema/crdb/add-webhooks/up09.sql b/schema/crdb/add-webhooks/up09.sql index 00e5cb3e7b..08a44f54e3 100644 --- a/schema/crdb/add-webhooks/up09.sql +++ b/schema/crdb/add-webhooks/up09.sql @@ -1,9 +1,12 @@ -CREATE TYPE IF NOT EXISTS omicron.public.webhook_msg_delivery_result as ENUM ( - -- The delivery attempt failed with an HTTP error. - 'failed_http_error', - -- The delivery attempt failed because the receiver endpoint was - -- unreachable. - 'failed_unreachable', - -- The delivery attempt succeeded. - 'succeeded' +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_dispatch ( + -- UUID of this dispatch. + id UUID PRIMARY KEY, + -- UUID of the webhook receiver (foreign key into + -- `omicron.public.webhook_rx`) + rx_id UUID NOT NULL, + payload JSONB NOT NULL, + time_created TIMESTAMPTZ NOT NULL, + -- If this is set, then this webhook message has either been delivered + -- successfully, or is considered permanently failed. + time_completed TIMESTAMPTZ, ); diff --git a/schema/crdb/add-webhooks/up10.sql b/schema/crdb/add-webhooks/up10.sql index 19f87bf459..4cc13a67cc 100644 --- a/schema/crdb/add-webhooks/up10.sql +++ b/schema/crdb/add-webhooks/up10.sql @@ -1,27 +1,5 @@ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_delivery_attempt ( - id UUID PRIMARY KEY, - -- Foreign key into `omicron.public.webhook_msg_dispatch`. - dispatch_id UUID NOT NULL, - result omicron.public.webhook_msg_delivery_result NOT NULL, - response_status INT2, - response_duration INTERVAL, - time_created TIMESTAMPTZ NOT NULL, - - CONSTRAINT response_iff_not_unreachable CHECK ( - ( - -- If the result is 'succeedeed' or 'failed_http_error', response - -- data must be present. - (result = 'succeeded' OR result = 'failed_http_error') AND ( - response_status IS NOT NULL AND - response_duration IS NOT NULL - ) - ) OR ( - -- If the result is 'failed_unreachable', no response data is - -- present. - (result = 'failed_unreachable') AND ( - response_status IS NULL AND - response_duration IS NULL - ) - ) - ) +-- Index for looking up all webhook messages dispatched to a receiver ID +CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx +ON omicron.public.webhook_msg_dispatch ( + rx_id ); diff --git a/schema/crdb/add-webhooks/up11.sql b/schema/crdb/add-webhooks/up11.sql index 2a32f10969..d7cb44b173 100644 --- a/schema/crdb/add-webhooks/up11.sql +++ b/schema/crdb/add-webhooks/up11.sql @@ -1,4 +1,7 @@ -CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg -ON omicron.public.webhook_msg_delivery_attempts ( - dispatch_id -); +-- Index for looking up all currently in-flight webhook messages, and ordering +-- them by their creation times. +CREATE INDEX IF NOT EXISTS webhook_dispatch_in_flight +ON omicron.public.webhook_msg_dispatch ( + time_created, id +) WHERE + time_completed IS NULL; diff --git a/schema/crdb/add-webhooks/up12.sql b/schema/crdb/add-webhooks/up12.sql new file mode 100644 index 0000000000..00e5cb3e7b --- /dev/null +++ b/schema/crdb/add-webhooks/up12.sql @@ -0,0 +1,9 @@ +CREATE TYPE IF NOT EXISTS omicron.public.webhook_msg_delivery_result as ENUM ( + -- The delivery attempt failed with an HTTP error. + 'failed_http_error', + -- The delivery attempt failed because the receiver endpoint was + -- unreachable. + 'failed_unreachable', + -- The delivery attempt succeeded. + 'succeeded' +); diff --git a/schema/crdb/add-webhooks/up13.sql b/schema/crdb/add-webhooks/up13.sql new file mode 100644 index 0000000000..19f87bf459 --- /dev/null +++ b/schema/crdb/add-webhooks/up13.sql @@ -0,0 +1,27 @@ +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_delivery_attempt ( + id UUID PRIMARY KEY, + -- Foreign key into `omicron.public.webhook_msg_dispatch`. + dispatch_id UUID NOT NULL, + result omicron.public.webhook_msg_delivery_result NOT NULL, + response_status INT2, + response_duration INTERVAL, + time_created TIMESTAMPTZ NOT NULL, + + CONSTRAINT response_iff_not_unreachable CHECK ( + ( + -- If the result is 'succeedeed' or 'failed_http_error', response + -- data must be present. + (result = 'succeeded' OR result = 'failed_http_error') AND ( + response_status IS NOT NULL AND + response_duration IS NOT NULL + ) + ) OR ( + -- If the result is 'failed_unreachable', no response data is + -- present. + (result = 'failed_unreachable') AND ( + response_status IS NULL AND + response_duration IS NULL + ) + ) + ) +); diff --git a/schema/crdb/add-webhooks/up14.sql b/schema/crdb/add-webhooks/up14.sql new file mode 100644 index 0000000000..2a32f10969 --- /dev/null +++ b/schema/crdb/add-webhooks/up14.sql @@ -0,0 +1,4 @@ +CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg +ON omicron.public.webhook_msg_delivery_attempts ( + dispatch_id +); diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index a3577848e4..84e1d0ca5a 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4724,7 +4724,7 @@ ON omicron.public.webhook_rx_secret ( ) WHERE time_deleted IS NULL; -CREATE TABLE IF NOT EXISTS omicron.public.webhook_subscription ( +CREATE TABLE IF NOT EXISTS omicron.public.webhook_rx_subscription ( -- UUID of the webhook receiver (foreign key into -- `omicron.public.webhook_rx`) rx_id UUID NOT NULL, @@ -4740,6 +4740,37 @@ ON omicron.public.webhook_rx_subscription ( rx_id ); +-- Look up all webhook receivers subscribed to an event class. This is used by +-- the dispatcher to determine who is interested in a particular event. +CREATE INDEX IF NOT EXISTS lookup_webhook_rxs_for_event +ON omicron.public.webhook_rx_subscription ( + event_class +); + +/* + * Webhook message queue. + */ + +CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg ( + id UUID PRIMARY KEY, + time_created TIMESTAMPTZ NOT NULL, + -- Set when dispatch entries have been created for this event. + time_dispatched TIMESTAMPTZ, + -- The class of event that this is. + event_class STRING(512) NOT NULL, + -- Actual event data. The structure of this depends on the event class. + event JSONB NOT NULL +); + +-- Look up webhook messages in need of dispatching. +-- +-- This is used by the message dispatcher when looking for messages to dispatch. +CREATE INDEX IF NOT EXISTS lookup_undispatched_webhook_msgs +ON omicron.public.webhook_msg ( + id, time_created +) WHERE time_dispatched IS NULL; + + /* * Webhook message dispatching and delivery attempts. */ From d80c4c9ce6a851fad9e7dd502d4ff838b3985e6d Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 18 Dec 2024 14:24:39 -0800 Subject: [PATCH 3/9] more diesel plumbing --- nexus/db-model/src/lib.rs | 2 + nexus/db-model/src/schema.rs | 75 ++++++++++++++++++++++ nexus/db-model/src/schema_versions.rs | 3 +- nexus/db-model/src/webhook_msg_delivery.rs | 30 +++++++++ schema/crdb/dbinit.sql | 2 +- 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 nexus/db-model/src/webhook_msg_delivery.rs diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index 66723e0b18..a5fb4479db 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -63,6 +63,7 @@ mod switch_interface; mod switch_port; mod v2p_mapping; mod vmm_state; +mod webhook_msg_delivery; // These actually represent subqueries, not real table. // However, they must be defined in the same crate as our tables // for join-based marker trait generation. @@ -127,6 +128,7 @@ mod db { pub use self::macaddr::*; pub use self::unsigned::*; +pub use self::webhook_msg_delivery::*; pub use address_lot::*; pub use allow_list::*; pub use bfd::*; diff --git a/nexus/db-model/src/schema.rs b/nexus/db-model/src/schema.rs index 399da81ea4..2b5bf1e69a 100644 --- a/nexus/db-model/src/schema.rs +++ b/nexus/db-model/src/schema.rs @@ -2108,3 +2108,78 @@ table! { region_snapshot_snapshot_id -> Nullable, } } + +table! { + webhook_rx (id) { + id -> Uuid, + name -> Text, + endpoint -> Text, + time_created -> Timestamptz, + time_modified -> Nullable, + time_deleted -> Nullable, + } +} + +table! { + webhook_rx_secret (rx_id, signature_id) { + rx_id -> Uuid, + signature_id -> Text, + secret -> Binary, + time_created -> Timestamptz, + time_deleted -> Nullable, + } +} + +allow_tables_to_appear_in_same_query!(webhook_rx, webhook_rx_secret); +joinable!(webhook_rx_secret -> webhook_rx (rx_id)); + +table! { + webhook_rx_subscription (rx_id, event_class) { + rx_id -> Uuid, + event_class -> Text, + time_created -> Timestamptz, + } +} + +allow_tables_to_appear_in_same_query!(webhook_rx, webhook_rx_subscription); +joinable!(webhook_rx_subscription -> webhook_rx (rx_id)); + +table! { + webhook_msg (id) { + id -> Uuid, + time_created -> Timestamptz, + time_dispatched -> Nullable, + event_class -> Text, + event -> Jsonb, + } +} + +table! { + webhook_msg_dispatch (id) { + id -> Uuid, + rx_id -> Uuid, + payload -> Jsonb, + time_created -> Timestamptz, + time_completed -> Nullable, + } +} + +allow_tables_to_appear_in_same_query!(webhook_rx, webhook_msg_dispatch); +joinable!(webhook_msg_dispatch -> webhook_rx (rx_id)); + +table! { + webhook_msg_delivery_attempt (id) { + id -> Uuid, + dispatch_id -> Uuid, + result -> crate::WebhookDeliveryResultEnum, + response_status -> Nullable, + response_duration -> Nullable, + time_created -> Timestamptz, + } +} + +allow_tables_to_appear_in_same_query!( + webhook_msg_dispatch, + webhook_msg_delivery_attempt +); +joinable!(webhook_msg_delivery_attempt -> webhook_msg_dispatch (dispatch_id)); diff --git a/nexus/db-model/src/schema_versions.rs b/nexus/db-model/src/schema_versions.rs index 02646bc6dd..dd5a3218cd 100644 --- a/nexus/db-model/src/schema_versions.rs +++ b/nexus/db-model/src/schema_versions.rs @@ -17,7 +17,7 @@ use std::collections::BTreeMap; /// /// This must be updated when you change the database schema. Refer to /// schema/crdb/README.adoc in the root of this repository for details. -pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(116, 0, 0); +pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(117, 0, 0); /// List of all past database schema versions, in *reverse* order /// @@ -29,6 +29,7 @@ static KNOWN_VERSIONS: Lazy> = Lazy::new(|| { // | leaving the first copy as an example for the next person. // v // KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"), + KnownVersion::new(117, "add-webhooks"), KnownVersion::new(116, "bp-physical-disk-disposition"), KnownVersion::new(115, "inv-omicron-physical-disks-generation"), KnownVersion::new(114, "crucible-ref-count-records"), diff --git a/nexus/db-model/src/webhook_msg_delivery.rs b/nexus/db-model/src/webhook_msg_delivery.rs new file mode 100644 index 0000000000..d9724ef9a5 --- /dev/null +++ b/nexus/db-model/src/webhook_msg_delivery.rs @@ -0,0 +1,30 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use super::impl_enum_type; +use serde::Deserialize; +use serde::Serialize; + +impl_enum_type!( + #[derive(SqlType, Debug, Clone)] + #[diesel(postgres_type(name = "webhook_msg_delivery_result", schema = "public"))] + pub struct WebhookDeliveryResultEnum; + + #[derive( + Copy, + Clone, + Debug, + PartialEq, + AsExpression, + FromSqlRow, + Serialize, + Deserialize, + )] + #[diesel(sql_type = WebhookDeliveryResultEnum)] + pub enum WebhookDeliveryResult; + + FailedHttpError => b"failed_http_error" + FailedUnreachable => b"failed_unreachable" + Succeeded => b"succeeded" +); diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index 84e1d0ca5a..224b76e09f 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4856,7 +4856,7 @@ INSERT INTO omicron.public.db_metadata ( version, target_version ) VALUES - (TRUE, NOW(), NOW(), '116.0.0', NULL) + (TRUE, NOW(), NOW(), '117.0.0', NULL) ON CONFLICT DO NOTHING; COMMIT; From 531c3bea0d650c7af35c900800bde95e62b69142 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 2 Jan 2025 14:48:58 -0800 Subject: [PATCH 4/9] terminology tweaks --- nexus/db-model/src/lib.rs | 4 +-- nexus/db-model/src/schema.rs | 18 ++++++------ nexus/db-model/src/webhook_msg_delivery.rs | 2 +- schema/crdb/add-webhooks/README.adoc | 22 +++++++------- schema/crdb/add-webhooks/up07.sql | 2 +- schema/crdb/add-webhooks/up08.sql | 4 +-- schema/crdb/add-webhooks/up09.sql | 2 +- schema/crdb/add-webhooks/up10.sql | 2 +- schema/crdb/add-webhooks/up11.sql | 4 +-- schema/crdb/add-webhooks/up12.sql | 2 +- schema/crdb/add-webhooks/up13.sql | 8 ++--- schema/crdb/add-webhooks/up14.sql | 4 +-- schema/crdb/dbinit.sql | 34 +++++++++++----------- 13 files changed, 54 insertions(+), 54 deletions(-) diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index a5fb4479db..b760678bee 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -63,7 +63,7 @@ mod switch_interface; mod switch_port; mod v2p_mapping; mod vmm_state; -mod webhook_msg_delivery; +mod webhook_event_delivery; // These actually represent subqueries, not real table. // However, they must be defined in the same crate as our tables // for join-based marker trait generation. @@ -128,7 +128,7 @@ mod db { pub use self::macaddr::*; pub use self::unsigned::*; -pub use self::webhook_msg_delivery::*; +pub use self::webhook_event_delivery::*; pub use address_lot::*; pub use allow_list::*; pub use bfd::*; diff --git a/nexus/db-model/src/schema.rs b/nexus/db-model/src/schema.rs index 2b5bf1e69a..a0939df213 100644 --- a/nexus/db-model/src/schema.rs +++ b/nexus/db-model/src/schema.rs @@ -2145,7 +2145,7 @@ allow_tables_to_appear_in_same_query!(webhook_rx, webhook_rx_subscription); joinable!(webhook_rx_subscription -> webhook_rx (rx_id)); table! { - webhook_msg (id) { + webhook_event (id) { id -> Uuid, time_created -> Timestamptz, time_dispatched -> Nullable, @@ -2155,7 +2155,7 @@ table! { } table! { - webhook_msg_dispatch (id) { + webhook_delivery (id) { id -> Uuid, rx_id -> Uuid, payload -> Jsonb, @@ -2164,13 +2164,13 @@ table! { } } -allow_tables_to_appear_in_same_query!(webhook_rx, webhook_msg_dispatch); -joinable!(webhook_msg_dispatch -> webhook_rx (rx_id)); +allow_tables_to_appear_in_same_query!(webhook_rx, webhook_delivery); +joinable!(webhook_delivery -> webhook_rx (rx_id)); table! { - webhook_msg_delivery_attempt (id) { + webhook_event_delivery_attempt (id) { id -> Uuid, - dispatch_id -> Uuid, + delivery_id -> Uuid, result -> crate::WebhookDeliveryResultEnum, response_status -> Nullable, response_duration -> Nullable, @@ -2179,7 +2179,7 @@ table! { } allow_tables_to_appear_in_same_query!( - webhook_msg_dispatch, - webhook_msg_delivery_attempt + webhook_delivery, + webhook_event_delivery_attempt ); -joinable!(webhook_msg_delivery_attempt -> webhook_msg_dispatch (dispatch_id)); +joinable!(webhook_event_delivery_attempt -> webhook_delivery (delivery_id)); diff --git a/nexus/db-model/src/webhook_msg_delivery.rs b/nexus/db-model/src/webhook_msg_delivery.rs index d9724ef9a5..2f25c0dbc7 100644 --- a/nexus/db-model/src/webhook_msg_delivery.rs +++ b/nexus/db-model/src/webhook_msg_delivery.rs @@ -8,7 +8,7 @@ use serde::Serialize; impl_enum_type!( #[derive(SqlType, Debug, Clone)] - #[diesel(postgres_type(name = "webhook_msg_delivery_result", schema = "public"))] + #[diesel(postgres_type(name = "webhook_event_delivery_result", schema = "public"))] pub struct WebhookDeliveryResultEnum; #[derive( diff --git a/schema/crdb/add-webhooks/README.adoc b/schema/crdb/add-webhooks/README.adoc index c913776b73..9eff8b16ea 100644 --- a/schema/crdb/add-webhooks/README.adoc +++ b/schema/crdb/add-webhooks/README.adoc @@ -24,28 +24,28 @@ looking up all event classes that a receiver ID is subscribed to. `omicron.public.webhook_rx_subscription` for looking up all receivers subscribed to a particular event class. * *Webhook message queue*: -** `up07.sql` creates the `omicron.public.webhook_msg` table, which contains the +** `up07.sql` creates the `omicron.public.webhook_event` table, which contains the queue of un-dispatched webhook events. The dispatcher operates on entries in this queue, dispatching the event to receivers and generating the payload for each receiver. -** `up08.sql` creates the `lookup_undispatched_webhook_msgs` index on -`omicron.public.webhook_msg` for looking up webhook messages which have not yet been +** `up08.sql` creates the `lookup_undispatched_webhook_events` index on +`omicron.public.webhook_event` for looking up webhook messages which have not yet been dispatched and ordering by their creation times. * *Webhook message dispatching and delivery attempts*: ** *Dispatch table*: -*** `up09.sql` creates the table `omicron.public.webhook_msg_dispatch`, which +*** `up09.sql` creates the table `omicron.public.webhook_delivery`, which tracks the webhook messages that have been dispatched to receivers. *** `up10.sql` creates an index `lookup_webhook_dispatched_to_rx` for looking up -entries in `omicron.public.webhook_msg_dispatch` by receiver ID. -*** `up11.sql` creates an index `webhook_dispatch_in_flight` for looking up all currently in-flight webhook -messages (entries in `omicron.public.webhook_msg_dispatch` where the +entries in `omicron.public.webhook_delivery` by receiver ID. +*** `up11.sql` creates an index `webhook_deliverey_in_flight` for looking up all currently in-flight webhook +messages (entries in `omicron.public.webhook_delivery` where the `time_completed` field has not been set). ** *Delivery attempts*: -*** `up12.sql` creates the enum `omicron.public.webhook_msg_delivery_result`, +*** `up12.sql` creates the enum `omicron.public.webhook_event_delivery_result`, representing the potential outcomes of a webhook delivery attempt. -*** `up13.sql` creates the table `omicron.public.webhook_msg_delivery_attempt`, +*** `up13.sql` creates the table `omicron.public.webhook_event_delivery_attempt`, which records each individual delivery attempt for a webhook message in the -`webhook_msg_dispatch` table. +`webhook_delivery` table. *** `up14.sql` creates an index `lookup_webhook_delivery_attempts_for_msg` on -`omicron.public.webhook_msg_delivery_attempt`, for looking up all attempts to +`omicron.public.webhook_event_delivery_attempt`, for looking up all attempts to deliver a message with a given dispatch ID. diff --git a/schema/crdb/add-webhooks/up07.sql b/schema/crdb/add-webhooks/up07.sql index ba667e930f..99e00dfaeb 100644 --- a/schema/crdb/add-webhooks/up07.sql +++ b/schema/crdb/add-webhooks/up07.sql @@ -1,4 +1,4 @@ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg ( +CREATE TABLE IF NOT EXISTS omicron.public.webhook_event ( id UUID PRIMARY KEY, time_created TIMESTAMPTZ NOT NULL, -- Set when dispatch entries have been created for this event. diff --git a/schema/crdb/add-webhooks/up08.sql b/schema/crdb/add-webhooks/up08.sql index e18c2cea1a..c64ae2db0d 100644 --- a/schema/crdb/add-webhooks/up08.sql +++ b/schema/crdb/add-webhooks/up08.sql @@ -1,7 +1,7 @@ -- Look up webhook messages in need of dispatching. -- -- This is used by the message dispatcher when looking for messages to dispatch. -CREATE INDEX IF NOT EXISTS lookup_undispatched_webhook_msgs -ON omicron.public.webhook_msg ( +CREATE INDEX IF NOT EXISTS lookup_undispatched_webhook_events +ON omicron.public.webhook_event ( id, time_created ) WHERE time_dispatched IS NULL; diff --git a/schema/crdb/add-webhooks/up09.sql b/schema/crdb/add-webhooks/up09.sql index 08a44f54e3..02d13a552b 100644 --- a/schema/crdb/add-webhooks/up09.sql +++ b/schema/crdb/add-webhooks/up09.sql @@ -1,4 +1,4 @@ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_dispatch ( +CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( -- UUID of this dispatch. id UUID PRIMARY KEY, -- UUID of the webhook receiver (foreign key into diff --git a/schema/crdb/add-webhooks/up10.sql b/schema/crdb/add-webhooks/up10.sql index 4cc13a67cc..412930194f 100644 --- a/schema/crdb/add-webhooks/up10.sql +++ b/schema/crdb/add-webhooks/up10.sql @@ -1,5 +1,5 @@ -- Index for looking up all webhook messages dispatched to a receiver ID CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx -ON omicron.public.webhook_msg_dispatch ( +ON omicron.public.webhook_delivery ( rx_id ); diff --git a/schema/crdb/add-webhooks/up11.sql b/schema/crdb/add-webhooks/up11.sql index d7cb44b173..b7f9d57c8c 100644 --- a/schema/crdb/add-webhooks/up11.sql +++ b/schema/crdb/add-webhooks/up11.sql @@ -1,7 +1,7 @@ -- Index for looking up all currently in-flight webhook messages, and ordering -- them by their creation times. -CREATE INDEX IF NOT EXISTS webhook_dispatch_in_flight -ON omicron.public.webhook_msg_dispatch ( +CREATE INDEX IF NOT EXISTS webhook_deliverey_in_flight +ON omicron.public.webhook_delivery ( time_created, id ) WHERE time_completed IS NULL; diff --git a/schema/crdb/add-webhooks/up12.sql b/schema/crdb/add-webhooks/up12.sql index 00e5cb3e7b..87d21c7df8 100644 --- a/schema/crdb/add-webhooks/up12.sql +++ b/schema/crdb/add-webhooks/up12.sql @@ -1,4 +1,4 @@ -CREATE TYPE IF NOT EXISTS omicron.public.webhook_msg_delivery_result as ENUM ( +CREATE TYPE IF NOT EXISTS omicron.public.webhook_event_delivery_result as ENUM ( -- The delivery attempt failed with an HTTP error. 'failed_http_error', -- The delivery attempt failed because the receiver endpoint was diff --git a/schema/crdb/add-webhooks/up13.sql b/schema/crdb/add-webhooks/up13.sql index 19f87bf459..89f3cff55b 100644 --- a/schema/crdb/add-webhooks/up13.sql +++ b/schema/crdb/add-webhooks/up13.sql @@ -1,8 +1,8 @@ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_delivery_attempt ( +CREATE TABLE IF NOT EXISTS omicron.public.webhook_event_delivery_attempt ( id UUID PRIMARY KEY, - -- Foreign key into `omicron.public.webhook_msg_dispatch`. - dispatch_id UUID NOT NULL, - result omicron.public.webhook_msg_delivery_result NOT NULL, + -- Foreign key into `omicron.public.webhook_delivery`. + delivery_id UUID NOT NULL, + result omicron.public.webhook_event_delivery_result NOT NULL, response_status INT2, response_duration INTERVAL, time_created TIMESTAMPTZ NOT NULL, diff --git a/schema/crdb/add-webhooks/up14.sql b/schema/crdb/add-webhooks/up14.sql index 2a32f10969..17853efbcb 100644 --- a/schema/crdb/add-webhooks/up14.sql +++ b/schema/crdb/add-webhooks/up14.sql @@ -1,4 +1,4 @@ CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg -ON omicron.public.webhook_msg_delivery_attempts ( - dispatch_id +ON omicron.public.webhook_event_delivery_attempts ( + delivery_id ); diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index 224b76e09f..dd6b52932d 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4748,10 +4748,10 @@ ON omicron.public.webhook_rx_subscription ( ); /* - * Webhook message queue. + * Webhook event message queue. */ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg ( +CREATE TABLE IF NOT EXISTS omicron.public.webhook_event ( id UUID PRIMARY KEY, time_created TIMESTAMPTZ NOT NULL, -- Set when dispatch entries have been created for this event. @@ -4762,11 +4762,11 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg ( event JSONB NOT NULL ); --- Look up webhook messages in need of dispatching. +-- Look up webhook events in need of dispatching. -- --- This is used by the message dispatcher when looking for messages to dispatch. -CREATE INDEX IF NOT EXISTS lookup_undispatched_webhook_msgs -ON omicron.public.webhook_msg ( +-- This is used by the message dispatcher when looking for events to dispatch. +CREATE INDEX IF NOT EXISTS lookup_undispatched_webhook_events +ON omicron.public.webhook_event ( id, time_created ) WHERE time_dispatched IS NULL; @@ -4775,7 +4775,7 @@ ON omicron.public.webhook_msg ( * Webhook message dispatching and delivery attempts. */ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_dispatch ( +CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( -- UUID of this dispatch. id UUID PRIMARY KEY, -- UUID of the webhook receiver (foreign key into @@ -4790,19 +4790,19 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_dispatch ( -- Index for looking up all webhook messages dispatched to a receiver ID CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx -ON omicron.public.webhook_msg_dispatch ( +ON omicron.public.webhook_delivery ( rx_id ); -- Index for looking up all currently in-flight webhook messages, and ordering -- them by their creation times. -CREATE INDEX IF NOT EXISTS webhook_dispatch_in_flight -ON omicron.public.webhook_msg_dispatch ( +CREATE INDEX IF NOT EXISTS webhook_deliverey_in_flight +ON omicron.public.webhook_delivery ( time_created, id ) WHERE time_completed IS NULL; -CREATE TYPE IF NOT EXISTS omicron.public.webhook_msg_delivery_result as ENUM ( +CREATE TYPE IF NOT EXISTS omicron.public.webhook_event_delivery_result as ENUM ( -- The delivery attempt failed with an HTTP error. 'failed_http_error', -- The delivery attempt failed because the receiver endpoint was @@ -4812,11 +4812,11 @@ CREATE TYPE IF NOT EXISTS omicron.public.webhook_msg_delivery_result as ENUM ( 'succeeded' ); -CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_delivery_attempt ( +CREATE TABLE IF NOT EXISTS omicron.public.webhook_event_delivery_attempt ( id UUID PRIMARY KEY, - -- Foreign key into `omicron.public.webhook_msg_dispatch`. - dispatch_id UUID NOT NULL, - result omicron.public.webhook_msg_delivery_result NOT NULL, + -- Foreign key into `omicron.public.webhook_delivery`. + delivery_id UUID NOT NULL, + result omicron.public.webhook_event_delivery_result NOT NULL, response_status INT2, response_duration INTERVAL, time_created TIMESTAMPTZ NOT NULL, @@ -4841,8 +4841,8 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_msg_delivery_attempt ( ); CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg -ON omicron.public.webhook_msg_delivery_attempts ( - dispatch_id +ON omicron.public.webhook_event_delivery_attempts ( + delivery_id ); /* From 11658d967d8573475ec3b0ad06cc16b7e0d64536 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 2 Jan 2025 14:55:40 -0800 Subject: [PATCH 5/9] change tracking of delivery attempts --- nexus/db-model/src/lib.rs | 4 ++-- nexus/db-model/src/schema.rs | 6 +++--- ...hook_msg_delivery.rs => webhook_delivery.rs} | 2 +- schema/crdb/add-webhooks/README.adoc | 6 +++--- schema/crdb/add-webhooks/up09.sql | 2 ++ schema/crdb/add-webhooks/up10.sql | 2 +- schema/crdb/add-webhooks/up11.sql | 2 +- schema/crdb/add-webhooks/up12.sql | 2 +- schema/crdb/add-webhooks/up13.sql | 9 ++++++--- schema/crdb/add-webhooks/up14.sql | 2 +- schema/crdb/dbinit.sql | 17 +++++++++++------ 11 files changed, 32 insertions(+), 22 deletions(-) rename nexus/db-model/src/{webhook_msg_delivery.rs => webhook_delivery.rs} (89%) diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index b760678bee..d28c41b8ed 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -63,7 +63,7 @@ mod switch_interface; mod switch_port; mod v2p_mapping; mod vmm_state; -mod webhook_event_delivery; +mod webhook_delivery; // These actually represent subqueries, not real table. // However, they must be defined in the same crate as our tables // for join-based marker trait generation. @@ -128,7 +128,6 @@ mod db { pub use self::macaddr::*; pub use self::unsigned::*; -pub use self::webhook_event_delivery::*; pub use address_lot::*; pub use allow_list::*; pub use bfd::*; @@ -228,6 +227,7 @@ pub use vpc_firewall_rule::*; pub use vpc_route::*; pub use vpc_router::*; pub use vpc_subnet::*; +pub use webhook_delivery::*; pub use zpool::*; // TODO: The existence of both impl_enum_type and impl_enum_wrapper is a diff --git a/nexus/db-model/src/schema.rs b/nexus/db-model/src/schema.rs index a0939df213..adb0084ba9 100644 --- a/nexus/db-model/src/schema.rs +++ b/nexus/db-model/src/schema.rs @@ -2168,7 +2168,7 @@ allow_tables_to_appear_in_same_query!(webhook_rx, webhook_delivery); joinable!(webhook_delivery -> webhook_rx (rx_id)); table! { - webhook_event_delivery_attempt (id) { + webhook_delivery_attempt (id) { id -> Uuid, delivery_id -> Uuid, result -> crate::WebhookDeliveryResultEnum, @@ -2180,6 +2180,6 @@ table! { allow_tables_to_appear_in_same_query!( webhook_delivery, - webhook_event_delivery_attempt + webhook_delivery_attempt ); -joinable!(webhook_event_delivery_attempt -> webhook_delivery (delivery_id)); +joinable!(webhook_delivery_attempt -> webhook_delivery (delivery_id)); diff --git a/nexus/db-model/src/webhook_msg_delivery.rs b/nexus/db-model/src/webhook_delivery.rs similarity index 89% rename from nexus/db-model/src/webhook_msg_delivery.rs rename to nexus/db-model/src/webhook_delivery.rs index 2f25c0dbc7..1133813a40 100644 --- a/nexus/db-model/src/webhook_msg_delivery.rs +++ b/nexus/db-model/src/webhook_delivery.rs @@ -8,7 +8,7 @@ use serde::Serialize; impl_enum_type!( #[derive(SqlType, Debug, Clone)] - #[diesel(postgres_type(name = "webhook_event_delivery_result", schema = "public"))] + #[diesel(postgres_type(name = "webhook_delivery_result", schema = "public"))] pub struct WebhookDeliveryResultEnum; #[derive( diff --git a/schema/crdb/add-webhooks/README.adoc b/schema/crdb/add-webhooks/README.adoc index 9eff8b16ea..7a51cafd7c 100644 --- a/schema/crdb/add-webhooks/README.adoc +++ b/schema/crdb/add-webhooks/README.adoc @@ -41,11 +41,11 @@ entries in `omicron.public.webhook_delivery` by receiver ID. messages (entries in `omicron.public.webhook_delivery` where the `time_completed` field has not been set). ** *Delivery attempts*: -*** `up12.sql` creates the enum `omicron.public.webhook_event_delivery_result`, +*** `up12.sql` creates the enum `omicron.public.webhook_delivery_result`, representing the potential outcomes of a webhook delivery attempt. -*** `up13.sql` creates the table `omicron.public.webhook_event_delivery_attempt`, +*** `up13.sql` creates the table `omicron.public.webhook_delivery_attempt`, which records each individual delivery attempt for a webhook message in the `webhook_delivery` table. *** `up14.sql` creates an index `lookup_webhook_delivery_attempts_for_msg` on -`omicron.public.webhook_event_delivery_attempt`, for looking up all attempts to +`omicron.public.webhook_delivery_attempt`, for looking up all attempts to deliver a message with a given dispatch ID. diff --git a/schema/crdb/add-webhooks/up09.sql b/schema/crdb/add-webhooks/up09.sql index 02d13a552b..c2ee13acdb 100644 --- a/schema/crdb/add-webhooks/up09.sql +++ b/schema/crdb/add-webhooks/up09.sql @@ -1,6 +1,8 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( -- UUID of this dispatch. id UUID PRIMARY KEY, + --- UUID of the event (foreign key into `omicron.public.webhook_event`). + event_id UUID NOT NULL, -- UUID of the webhook receiver (foreign key into -- `omicron.public.webhook_rx`) rx_id UUID NOT NULL, diff --git a/schema/crdb/add-webhooks/up10.sql b/schema/crdb/add-webhooks/up10.sql index 412930194f..0e67ca550f 100644 --- a/schema/crdb/add-webhooks/up10.sql +++ b/schema/crdb/add-webhooks/up10.sql @@ -1,5 +1,5 @@ -- Index for looking up all webhook messages dispatched to a receiver ID CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx ON omicron.public.webhook_delivery ( - rx_id + rx_id, event_id ); diff --git a/schema/crdb/add-webhooks/up11.sql b/schema/crdb/add-webhooks/up11.sql index b7f9d57c8c..3b4532836d 100644 --- a/schema/crdb/add-webhooks/up11.sql +++ b/schema/crdb/add-webhooks/up11.sql @@ -1,4 +1,4 @@ --- Index for looking up all currently in-flight webhook messages, and ordering +-- Index for looking up all currently in-flight webhook deliveries, and ordering -- them by their creation times. CREATE INDEX IF NOT EXISTS webhook_deliverey_in_flight ON omicron.public.webhook_delivery ( diff --git a/schema/crdb/add-webhooks/up12.sql b/schema/crdb/add-webhooks/up12.sql index 87d21c7df8..dbe765f906 100644 --- a/schema/crdb/add-webhooks/up12.sql +++ b/schema/crdb/add-webhooks/up12.sql @@ -1,4 +1,4 @@ -CREATE TYPE IF NOT EXISTS omicron.public.webhook_event_delivery_result as ENUM ( +CREATE TYPE IF NOT EXISTS omicron.public.webhook_delivery_result as ENUM ( -- The delivery attempt failed with an HTTP error. 'failed_http_error', -- The delivery attempt failed because the receiver endpoint was diff --git a/schema/crdb/add-webhooks/up13.sql b/schema/crdb/add-webhooks/up13.sql index 89f3cff55b..4bc92ef3d5 100644 --- a/schema/crdb/add-webhooks/up13.sql +++ b/schema/crdb/add-webhooks/up13.sql @@ -1,12 +1,15 @@ -CREATE TABLE IF NOT EXISTS omicron.public.webhook_event_delivery_attempt ( - id UUID PRIMARY KEY, +CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery_attempt ( -- Foreign key into `omicron.public.webhook_delivery`. delivery_id UUID NOT NULL, - result omicron.public.webhook_event_delivery_result NOT NULL, + -- attempt number. + attempt INT2 NOT NULL, + result omicron.public.webhook_delivery_result NOT NULL, response_status INT2, response_duration INTERVAL, time_created TIMESTAMPTZ NOT NULL, + PRIMARY KEY (delivery_id, attempt), + CONSTRAINT response_iff_not_unreachable CHECK ( ( -- If the result is 'succeedeed' or 'failed_http_error', response diff --git a/schema/crdb/add-webhooks/up14.sql b/schema/crdb/add-webhooks/up14.sql index 17853efbcb..05ec2ba0c9 100644 --- a/schema/crdb/add-webhooks/up14.sql +++ b/schema/crdb/add-webhooks/up14.sql @@ -1,4 +1,4 @@ CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg -ON omicron.public.webhook_event_delivery_attempts ( +ON omicron.public.webhook_delivery_attempts ( delivery_id ); diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index dd6b52932d..4d173b3f43 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4778,6 +4778,8 @@ ON omicron.public.webhook_event ( CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( -- UUID of this dispatch. id UUID PRIMARY KEY, + --- UUID of the event (foreign key into `omicron.public.webhook_event`). + event_id UUID NOT NULL, -- UUID of the webhook receiver (foreign key into -- `omicron.public.webhook_rx`) rx_id UUID NOT NULL, @@ -4791,7 +4793,7 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( -- Index for looking up all webhook messages dispatched to a receiver ID CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx ON omicron.public.webhook_delivery ( - rx_id + rx_id, event_id, ); -- Index for looking up all currently in-flight webhook messages, and ordering @@ -4802,7 +4804,7 @@ ON omicron.public.webhook_delivery ( ) WHERE time_completed IS NULL; -CREATE TYPE IF NOT EXISTS omicron.public.webhook_event_delivery_result as ENUM ( +CREATE TYPE IF NOT EXISTS omicron.public.webhook_delivery_result as ENUM ( -- The delivery attempt failed with an HTTP error. 'failed_http_error', -- The delivery attempt failed because the receiver endpoint was @@ -4812,15 +4814,18 @@ CREATE TYPE IF NOT EXISTS omicron.public.webhook_event_delivery_result as ENUM ( 'succeeded' ); -CREATE TABLE IF NOT EXISTS omicron.public.webhook_event_delivery_attempt ( - id UUID PRIMARY KEY, +CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery_attempt ( -- Foreign key into `omicron.public.webhook_delivery`. delivery_id UUID NOT NULL, - result omicron.public.webhook_event_delivery_result NOT NULL, + -- attempt number. + attempt INT2 NOT NULL, + result omicron.public.webhook_delivery_result NOT NULL, response_status INT2, response_duration INTERVAL, time_created TIMESTAMPTZ NOT NULL, + PRIMARY KEY (delivery_id, attempt), + CONSTRAINT response_iff_not_unreachable CHECK ( ( -- If the result is 'succeedeed' or 'failed_http_error', response @@ -4841,7 +4846,7 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_event_delivery_attempt ( ); CREATE INDEX IF NOT EXISTS lookup_webhook_delivery_attempts_for_msg -ON omicron.public.webhook_event_delivery_attempts ( +ON omicron.public.webhook_delivery_attempts ( delivery_id ); From c858040c7a28c4bae7228b7a3d21aacb6b9a17bf Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 2 Jan 2025 14:56:29 -0800 Subject: [PATCH 6/9] s/deliverey/delivery --- schema/crdb/add-webhooks/README.adoc | 2 +- schema/crdb/add-webhooks/up11.sql | 2 +- schema/crdb/dbinit.sql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/schema/crdb/add-webhooks/README.adoc b/schema/crdb/add-webhooks/README.adoc index 7a51cafd7c..6f724c75f1 100644 --- a/schema/crdb/add-webhooks/README.adoc +++ b/schema/crdb/add-webhooks/README.adoc @@ -37,7 +37,7 @@ dispatched and ordering by their creation times. tracks the webhook messages that have been dispatched to receivers. *** `up10.sql` creates an index `lookup_webhook_dispatched_to_rx` for looking up entries in `omicron.public.webhook_delivery` by receiver ID. -*** `up11.sql` creates an index `webhook_deliverey_in_flight` for looking up all currently in-flight webhook +*** `up11.sql` creates an index `webhook_delivery_in_flight` for looking up all currently in-flight webhook messages (entries in `omicron.public.webhook_delivery` where the `time_completed` field has not been set). ** *Delivery attempts*: diff --git a/schema/crdb/add-webhooks/up11.sql b/schema/crdb/add-webhooks/up11.sql index 3b4532836d..b3c36debbb 100644 --- a/schema/crdb/add-webhooks/up11.sql +++ b/schema/crdb/add-webhooks/up11.sql @@ -1,6 +1,6 @@ -- Index for looking up all currently in-flight webhook deliveries, and ordering -- them by their creation times. -CREATE INDEX IF NOT EXISTS webhook_deliverey_in_flight +CREATE INDEX IF NOT EXISTS webhook_delivery_in_flight ON omicron.public.webhook_delivery ( time_created, id ) WHERE diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index 4d173b3f43..b1ef145d1c 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4798,7 +4798,7 @@ ON omicron.public.webhook_delivery ( -- Index for looking up all currently in-flight webhook messages, and ordering -- them by their creation times. -CREATE INDEX IF NOT EXISTS webhook_deliverey_in_flight +CREATE INDEX IF NOT EXISTS webhook_delivery_in_flight ON omicron.public.webhook_delivery ( time_created, id ) WHERE From d0048eb1053fd8219b55d253c1b9c4c7849af003 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 2 Jan 2025 15:12:31 -0800 Subject: [PATCH 7/9] add 'failed_timeout' delivery result --- nexus/db-model/src/webhook_delivery.rs | 1 + schema/crdb/add-webhooks/up12.sql | 3 +++ schema/crdb/add-webhooks/up13.sql | 6 +++--- schema/crdb/dbinit.sql | 9 ++++++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/nexus/db-model/src/webhook_delivery.rs b/nexus/db-model/src/webhook_delivery.rs index 1133813a40..6819b5a240 100644 --- a/nexus/db-model/src/webhook_delivery.rs +++ b/nexus/db-model/src/webhook_delivery.rs @@ -26,5 +26,6 @@ impl_enum_type!( FailedHttpError => b"failed_http_error" FailedUnreachable => b"failed_unreachable" + FailedTimeout => b"failed_timeout" Succeeded => b"succeeded" ); diff --git a/schema/crdb/add-webhooks/up12.sql b/schema/crdb/add-webhooks/up12.sql index dbe765f906..06ce311062 100644 --- a/schema/crdb/add-webhooks/up12.sql +++ b/schema/crdb/add-webhooks/up12.sql @@ -4,6 +4,9 @@ CREATE TYPE IF NOT EXISTS omicron.public.webhook_delivery_result as ENUM ( -- The delivery attempt failed because the receiver endpoint was -- unreachable. 'failed_unreachable', + --- The delivery attempt connected successfully but no response was received + -- within the timeout. + 'failed_timeout', -- The delivery attempt succeeded. 'succeeded' ); diff --git a/schema/crdb/add-webhooks/up13.sql b/schema/crdb/add-webhooks/up13.sql index 4bc92ef3d5..3497555f78 100644 --- a/schema/crdb/add-webhooks/up13.sql +++ b/schema/crdb/add-webhooks/up13.sql @@ -19,9 +19,9 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery_attempt ( response_duration IS NOT NULL ) ) OR ( - -- If the result is 'failed_unreachable', no response data is - -- present. - (result = 'failed_unreachable') AND ( + -- If the result is 'failed_unreachable' or 'failed_timeout', no + -- response data is present. + (result = 'failed_unreachable' OR result = 'failed_timeout') AND ( response_status IS NULL AND response_duration IS NULL ) diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index b1ef145d1c..9af49c350f 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4810,6 +4810,9 @@ CREATE TYPE IF NOT EXISTS omicron.public.webhook_delivery_result as ENUM ( -- The delivery attempt failed because the receiver endpoint was -- unreachable. 'failed_unreachable', + --- The delivery attempt connected successfully but no response was received + -- within the timeout. + 'failed_timeout', -- The delivery attempt succeeded. 'succeeded' ); @@ -4835,9 +4838,9 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery_attempt ( response_duration IS NOT NULL ) ) OR ( - -- If the result is 'failed_unreachable', no response data is - -- present. - (result = 'failed_unreachable') AND ( + -- If the result is 'failed_unreachable' or 'failed_timeout', no + -- response data is present. + (result = 'failed_unreachable' OR result = 'failed_timeout') AND ( response_status IS NULL AND response_duration IS NULL ) From 11d3b1525e9ed762721ded96cec34c655c1b4a71 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 2 Jan 2025 15:45:13 -0800 Subject: [PATCH 8/9] ag --- schema/crdb/add-webhooks/up09.sql | 2 +- schema/crdb/dbinit.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/schema/crdb/add-webhooks/up09.sql b/schema/crdb/add-webhooks/up09.sql index c2ee13acdb..41c9993413 100644 --- a/schema/crdb/add-webhooks/up09.sql +++ b/schema/crdb/add-webhooks/up09.sql @@ -10,5 +10,5 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( time_created TIMESTAMPTZ NOT NULL, -- If this is set, then this webhook message has either been delivered -- successfully, or is considered permanently failed. - time_completed TIMESTAMPTZ, + time_completed TIMESTAMPTZ ); diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index 9af49c350f..1535189fd5 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4787,7 +4787,7 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( time_created TIMESTAMPTZ NOT NULL, -- If this is set, then this webhook message has either been delivered -- successfully, or is considered permanently failed. - time_completed TIMESTAMPTZ, + time_completed TIMESTAMPTZ ); -- Index for looking up all webhook messages dispatched to a receiver ID From 001dd2284105f777cf8f78fa96df23a3c3e8545b Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 2 Jan 2025 15:48:04 -0800 Subject: [PATCH 9/9] ag --- schema/crdb/dbinit.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index 1535189fd5..b6a0e67854 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -4793,7 +4793,7 @@ CREATE TABLE IF NOT EXISTS omicron.public.webhook_delivery ( -- Index for looking up all webhook messages dispatched to a receiver ID CREATE INDEX IF NOT EXISTS lookup_webhook_dispatched_to_rx ON omicron.public.webhook_delivery ( - rx_id, event_id, + rx_id, event_id ); -- Index for looking up all currently in-flight webhook messages, and ordering