-
Notifications
You must be signed in to change notification settings - Fork 7
Home
In general, Webhooks are a common asynchronous means today for listening to key 'events' raised by online systems, typically over HTTPS.
The idea is straightforward:
- Register a callback URL to be called when an "event" of a certain type is going to be raised, and the system will POST you notification of that event (along with any data describing that event) to that callback URL when the event is raised.
- You first need to register the callback URL with the system for a specific event (which implies a specific DTO of the event data).
- Sit back and wait to be called at your callback URL.
Under the covers, Webhooks are a good example of pub/sub architectures, where the consumers of the events are (typically) decoupled from the producer of the events. It is generally an asynchronous eventing system for the web.
In this project, we are basing the subscription model of webhooks on that defined by GitHub Webhooks.
Which, defines the subscription service interface, and the wire representations of published events.
- Subscription Service Definition (except ping)
- Event Payloads
The WebhookFeature
will be a ServiceStack Plugin that installs the following:
- A fully implemented and secured
SubscriptionService
, that allows any subscriber to register a webhook to any event raised by any service (in the same AppHost). - A singleton service
IWebhooks
that will be used to raise any event from anywhere in any service in the AppHost. - An extensible framework where the developer can plugin selected technologies that fit their service architecture and runtime environment.
- Default implementations of the key components in the architecture to support the delivery of events to registered subscribers.
You add webhooks to your ServiceStack project by simply registering (and customizing) the WebhookFeature
in your AppHost.cs.
public override void Configure(Container container)
{
// Register the ValidationFeature and AuthFeature first
Plugins.Add(new ValidationFeature());
Plugins.Add(new AuthFeature(...));
Plugins.Add(new WebhookFeature
{
.. any customization for your environment
});
}
The WebhookFeature
comes with a built-in ISubscriptionStore
and a built-in IEventSink
that you can use to get up an running quickly.
WARNING: In any production environment you are going to need to register a ISubscriptionStore
and IEventSink
that suits your architecture, since the built-in ones are really only designed for getting up and running quickly, and for testing.
public override void Configure(Container container)
{
// Register the ValidationFeature and AuthFeature first
Plugins.Add(new ValidationFeature());
Plugins.Add(new AuthFeature(...));
// Register your own ISubscriptionStore and IEventSink
container.Register<ISubscriptionStore>(new MyDbSubscriptionStore());
container.Register<IEventSink>(new MyAsyncEventSink());
Plugins.Add(new WebhookFeature
{
.. any customization for your environment
});
}
See Getting Started for more details
There are several points of extensibility in the WebhookFeature
, and each may support their own customization:
By default the WebHookFeature
registers and configures the SubscriptionService
to provide an API for subscribers to manage their webhooks.
You can choose to turn this service off, and ship your own, and you can also configure the authorization roles that secure it.
See Subscription Service for more details on how to customize it
Subscriptions for webhooks need to be stored (ISubscriptionStore
) after a user of your service subscribes to a webhook using the API: POST /webhooks/subscriptions
.
You specify your own store by registering it in the IOC container. If you specify no store, the default MemorySubscriptionStore
will be used, which is fine for testing, but beware that your subscriptions will be lost whenever your AppHost is restarted.
You should register a different ISubscriptionStore
that will persist subscriptions to some permanent (and perhaps distributed) store in your architecture.
These stores are typically provided by extensions to the ServiceStack.Webhooks
framework such as those listed in: Plugins
public override void Configure(Container container)
{
// Register your own subscription store
container.Register<ISubscriptionStore>(new MyDbSubscriptionStore());
Plugins.Add(new WebhookFeature();
}
WARNING: The MemorySubscriptionStore
is not designed for use in production systems. If you do NOT register your own ISubscriptionStore
your subscriptions will be lost when your AppHost restarts!
When events are raised they are passed to the event sink (IEventSink
), typically temporarily, until they are "relayed" to all registered subscribers for that event. Remember that raising a single event might result in (potentially) hundreds of subscribers being notified!
Ideally, for scalability and performance, you would not want to notify all those subscribers on the same thread that raised the event. Probably not even by the same process that raised them. Ideally, that workload is passed onto another process while your services stay responsive.
You specify your own sink by registering it in the IOC container.
If you specify no sink, the default AppHostEventSink
will be used, which is fine for testing, but beware that this sink works synchronously on the same thread that raises the event, and so it is not optimal for scale in production systems.
The AppHostEventSink
will relay events to all subscribers in the same thread that called IWebhooks.Publish<TDto>()
.
You should register a different IEventSink
that will decouple the raising of events from the relays of events to subscribers, using appropriate components in your architecture. (i.e. muti-threading, queues, async hooks etc.)
These kinds of sinks are typically provided by extensions to the ServiceStack.Webhooks
framework such as those listed in: Plugins
public override void Configure(Container container)
{
// Register your own event store
container.Register<IEventSink>(new MyDbEventSink());
Plugins.Add(new WebhookFeature();
}
WARNING: The AppHostEventSink
is not designed for use in production systems. If you do NOT register your own IEventSink
your services will suffer unacceptable performance penalties.