The easy way to trigger any HTTP service
TriggerMesh is a powerful open-source solution for building event-driven applications. One of the defining characteristics of TriggerMesh and similar event brokers like Amazon EventBridge, Azure EventGrid, and Google EventArc, is that they are push-based. This means that events are pushed to consumers, as opposed to consumers pulling events from the broker like they would with Kafka or most queue-based systems. This makes TriggerMesh very well suited to triggering HTTP-based services such as Google Cloud functions, Google Cloud Run services, Azure Functions, Knative services, or microservices. In this post, we’ll make use of improvements to the HTTP Target in 1.25 that make it simpler than ever to trigger any HTTP service with events from TriggerMesh's broad range of event sources.
If on the other hand your service specifically expects a CloudEvent as an input, or you'd like an example of how to build a CloudEvents service from the ground up, then take a look at this post that shows how to build a CloudEvents Knative service using Python FastAPI and route CloudEvents to it with TriggerMesh.
The general idea for this post is illustrated below :
In this example, I'm going to deploy a simple service called the http-order-service, that receives a POST request on /orders , where the payload contains a JSON object representing an order. The service prints the order to standard out and responds to the caller with Order received. when things go well. We'll use TriggerMesh to expose another HTTP endpoint (the Webhook source) whose role will be to produce events into the TriggerMesh broker. We're using the Webhook source as an example here that doesn't require any external dependencies, but you could easily replace this with something like a Kafka source, AWS SQS source, Google Pub/Sub source, or Azure Service Bus source, among others.
As always, be sure to join the TriggerMesh community Slack so we can help you make the best of your event-driven journey 😀.
Local development with Docker and tmctl
As you may know, TriggerMesh comes in two flavours: local development with our CLI called tmctl which only requires Docker as a prerequisite. The other flavour is TriggerMesh on Kubernetes, thanks to our provided custom resources and controllers, and Helm charts or YAML files to install them.
We'll start with local development, then show you how you can easily transition what you've done to a Kubernetes cluster (Minikube shown here).
If you haven't already, make sure you've installed tmctl (e.g. brew install triggermesh/cli/tmctl) and that you have Docker on your machine.
Run the following sequence of commands to create the necessary components to run this example locally.
The first line creates a TriggerMesh broker that will receive and buffer events. The second line creates a Webhook source, which acts as an HTTP endpoint to which you can send events, which will be passed to the broker. We're explicitly setting the type of all events coming from the Webhook source to com.acme.orders.orderCreated. Then we're creating an HTTP target that is configured to send events as JSON to our HTTP service using the POST method on path /orders. We then create a trigger which tells the broker to send events of type com.acme.orders.orderCreated to the HTTP target.
The last line deploys a simple example HTTP service (built by yours truly) that expects a JSON object representing an order to arrive via HTTP POST on path /orders. If you already have your own HTTP service that you want to route events to (Cloud Run service, function, etc...) you can omit the docker run command, and modify the http target's --endpoint parameter to point to your service instead. For example, if you have a Cloud Run service available at a public URL like https://triggermesh-console-tu4luqbmqq-uc.a.run.app, then you can set the --endpoint parameter for the HTTP target to that value.
After running these commands, if you now run tmctl describe, you should see the components you've created:
You can also run docker ps to make sure the http-order-service is up and running (you'll also see the TriggerMesh components running, except the Trigger which is built into the Broker):
Test it out
Before doing anything else, lets start a new terminal and run tmctl watch so that we can observe events passing through the broker.
Now that everything is running, we can send an order JSON object into the Webhook source using curl. Note the URL next to the Webhook source in the tmctl describe output, you'll need to modify this to use your own value for the curl URL:
In the tmctl watch terminal, you should see two CloudEvents appear:
The first event was sent to the broker by the Webhook source, after making the curl request. You can see that the payload of the HTTP request has been wrapped into the Data attribute, and that CloudEvents metadata has been added to the event.
The second event is actually the response from the external HTTP service that I've routed the event to, confirming that it has correctly received the event from the HTTP target. Success 👌.
In case you're wondering, the HTTP target will create a new event from the response it got from the external target. You don't have to use this response, but if you wanted to you could write another Trigger on the Broker that fires when the HTTP service responds, to trigger an additional action.
We can also check the logs of the http-order-service docker container (update the container ID to your own):
As you can see the service has successfully received the event and logged it.
As a next step, if you haven't already done so you could replace the docker http-order-service by your own service, and replace the webhook source with your own source of events such as Kafka, SQS, or any of the other event sources supported by TriggerMesh.
Read on if you want to learn about how to run the same event flow on Kubernetes.
Once we've implemented our application with tmctl, it is very easy to export is as a Kubernetes manifest by using the tmctl dump command. Try it and see for yourself! Before I do it here though, I'm going to do a couple more things with tmctl first. See, the http-order-service is currently running as a Docker container and won't be accessible to TriggerMesh if the latter is running on Kubernetes. So I'm going to use a little trick that will let me turn the http-order-service into a Knative service that'll run on Kubernetes. To do this, I'll run the following command:
This command will run my http-order-service and make it available as a TriggerMesh target from tmctl. This can be very useful, but that not exactly how I'm going to use it just now. The other effect this command has is that this service will now become a Knative service when I do tmctl dump. Lets run it now and have a look:
As expected, the output manifest contains a definition of my Broker, Webhook source, HTTP target, Trigger, and the newly added http-order-service in the form of a Knative service. We're going to use this as a basis for running the example on Kubernetes.
If you haven’t already done so, you’ll need to install TriggerMesh and Knative Serving on your cluster. I’m using minikube (minikube start) to create a local cluster and I followed the guide for installing TriggerMesh and Knative Serving onto the cluster. The whole process should only take a few minutes.
Once you've installed TriggerMesh (and Knative) on Minikube, apply the previously dumped manifest to the cluster:
If you view the pods in the default namespace, you'll now see pods corresponding to the different TriggerMesh components and the http-order-service (called triggermesh-target-service). Note that because the Webhook source, the HTTP target, and the http-order-service all run as Knative services, they will scale to 0 when idle, so you might need to send events into the system before you see the pods spin up. In my case, they're spinning up initially before they scale down to 0, so I can see the pods like so:
Lets get the cluster-local address of our http-order-service so that we can update the HTTP target's endpoint to that value:
Now update the relevant part of the manifest.yaml, i.e. the HTTP target's endpoint (don't forget the /orders path at the end of the URL):
And apply the manifest again so that the endpoint gets updated:
Test it out!
Run minikube tunnel in a separate terminal, so that the load balancer service is assigned an IP. That loadbalancer IP is used by the sslip.io config.
Run the command below to get the webhook source’s URL (accessible outside of the cluster thanks to minikube tunnel).
Then send an event into your webhook source:
Quickly run kubectl get pods and if all went well, you should see the HTTP target pods, the Webhook source pods, and the http-order-service pods (called triggermesh-target-service) spin up:
Again, these three services run as Knative services, which is why you’ll only see their pods appear when there are events to process (else they scale down to 0).
If you look at the pod logs for the http-order-service, you’ll see that it has received the event:
The goal of this post was to show how to trigger any HTTP service such as a cloud function, knative service, or any other service with an HTTP endpoint. We ran through an example with tmctl, and then showed how you can transition this to something similar on Kubernetes.
Improvements in the 1.25 release have made this much easier, because now by default the HTTP target will take the value of the Data attribute (your event payload), and pass it as the HTTP payload to its destination. Prior to 1.25, some transformation was required before you could do this.
Now that you’ve seen how to do this, you can easily use other event sources to trigger the service other than the Webhook source shown in this demo. For instance, you could try triggering it when an event lands on an AWS SQS queue, a Google Pub/Sub topic, or an Azure Event Hub.
If you got this far, let us know all about it on Slack! We'd love to hear from you, and are always happy to help.