Skip to content

Building Your Own Plugin

Jezz Santos edited this page Mar 11, 2017 · 20 revisions

ServiceStack.Webhooks supports the ability to fit within any architecture you may have your services deployed in.

It's as simple as providing your own IEventSink and ISubscriptionStore, and plugging it into your WebhookFeature.

Developing your own SubscriptionStore plugin (ISubscriptionStore

There is not much to be said about creating your own 'ISubscriptionStore' it is very straightforward to create an adapter to a data store of your choice. It just has a simple CRUD-like interface that you'll need to implement.

public interface ISubscriptionStore
    {
        /// <summary>
        ///     Returns the identity of the added subscription
        /// </summary>
        string Add(WebhookSubscription subscription);

        /// <summary>
        ///     Returns all subscription for the specified userId
        /// </summary>
        List<WebhookSubscription> Find(string userId);

        /// <summary>
        ///     Gets the subscription for the specified user and eventName
        /// </summary>
        WebhookSubscription Get(string userId, string eventName);

        /// <summary>
        ///     Gets the specified subscription
        /// </summary>
        WebhookSubscription Get(string subscriptionId);

        /// <summary>
        ///     Updates the specified subscription
        /// </summary>
        void Update(string subscriptionId, WebhookSubscription subscription);

        /// <summary>
        ///     Deletes the specified subscription
        /// </summary>
        void Delete(string subscriptionId);

        /// <summary>
        ///     Returns all subscription configurations for all users for the specified event,
        ///     and optionally whether they are currently active or not
        /// </summary>
        List<SubscriptionRelayConfig> Search(string eventName, bool? isActive);

        /// <summary>
        ///     Adds a new delivery result to the subscription
        /// </summary>
        void Add(string subscriptionId, SubscriptionDeliveryResult result);

        /// <summary>
        ///     Returns the top specified delivery results for the specified subscription (in descending date order)
        /// </summary>
        List<SubscriptionDeliveryResult> Search(string subscriptionId, int top);
    }

Simply:

  1. Install the nuget package 'Webhooks.Interfaces'.
  2. Implement the 'ISubscriptionStore' interface.
  3. See the Installation notes below.

Developing your own EventSink plugin (IEventSink)

However, creating your own 'IEventSink' is not quite so straightforward.

Implementing the interface is a doddle, but the infrastructure you have behind it isn't.

public interface IEventSink
    {
        /// <summary>
        ///     Writes a new event with data
        /// </summary>
        void Write(string eventName, Dictionary<string, string> data);
    }

Design your sink

Before you start cutting any code, you will need a plan for your new IEventSink plugin. In general the sink plugin is going to need two parts:

  • Sink - The first part is generally going to need to use some (asynchronous) and reliable, messaging technology that won't fail, and that 'stores-and-forwards' the raised event
  • Relay - the second part picks up the event and delivers it to all registered subscribers (dealing with network latency, availability, network connectivity issues and retries etc.).

There are many ways to do this combo, but commonly a ServiceBus or Queue is used as the 'Sink' part, and then some another compute service (i.e separate elastic process) performs the 'Relay' part.

You can see an example of that in the ServiceStack.Webooks.Azure plugin. But there are many others ways to solve this problem even with Azure.

The choice is entirely yours.

However, please consider the following in your design:

  • All events that are raised from your service, will be passed (synchronously) from your service code to the configured Sink IEventSink. Therefore, you will want to avoid doing too much processing at this point, otherwise calls to your service will suffer that performance penalty every time.
  • You will want the Relay process that picks up the events and delivers them to subscribers to do that reliably, otherwise if events are lost subscribers don't get notified, and downstream tool-chains that rely on those webhooks won't be executed. Not a fabulous user experience for your subscribers!
  • The 'Relay' component that you choose to sent events to subscribers over HTTP, is likely to be asynchronous, and ideally highly responsive and elastic (scales to demand), and will want to implement some kind of timeout and some kind of retry mechanism, since you don't want to assume that subscribers endpoints are always online all the time, and that their subscription configuration is necessarily valid at the time of delivery.

And just quietly....a reminder about these fallicies just in case your assuming any of them.

Having said all that, there are a bunch of cloud technologies that do all that kind of stuff for you, all you have to do is learn how to wield them, and use them as they are intended to be used.

Once you have all that sorted, create your 'IEventSink'.

Implement your sink

  1. Install the nuget package 'Webhooks.Interfaces'.
  2. Implement the 'IEventSink' interface.
  3. See the Installation notes below.

Installing your own Plugins

This is the easy part, once you have your plugin installed from either a nuget package, or referenced the same solution as your 'WebhookFeature', then just register it in your AppHost:

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 YourDbSubscriptionStore());
    container.Register<IEventSink>(new YourEventSink());

    Plugins.Add(new WebhookFeature
    {
        .. any customization for your environment
    });
}

Sit back, and start raising events from your service! And let your plugins do all the hard work.

Tell us about it!

One last thing. Don;t forget to tell us about your neat plugin, so that we can publish it on our Plugins page for other to use. Good luck!

Clone this wiki locally