Going Serverless with OpenWhisk
I have been using Webhooks for a long time now. Webhooks are HTTP callbacks. They usually get called with HTTP Post request on an event. For example system one does a POST request on system two when something changes on system one. These are typically used by heterogeneous systems for plumbing.
In my case there would be couple of notifications per day but the receiving system was a standard web app which was running 24x7 even though it wasn’t necessary. So instead of running on independent machine i started looking for a hosted services. Hook.io was one the services I used. Its simple, stable and it’s open source. You can host it yourself if you ever want. It really worked well.
Overtime my requirements grew and also I started working on an enterprise level project that needed more than simple Webhooks. I wanted to run small functions synchronously, asynchronously and sometimes on a schedule. One way was to do my own queues, scripts and scheduler. Other way was to look into Serverless architecture.
Apache OpenWhisk
There are many hosted serverless systems today. But I was looking for a system which was open source and can be hosted on premises if required. Whether it’s for an enterprise or for an indie project vendor lock-ins are bad. I prefer systems which allows one to export data, code, process etc and allows them to host it themselves. Apache OpenWhisk was probably the best serverless architecture that fit all these requirements and of course along with standard technical requirements of any serverless architecture.
I am quoting the definition of OpenWhisk from their website as its precise
OpenWhisk is an open source, distributed serverless computing platform able to execute application logic (Actions) in response to events (Triggers) from external sources (Feeds) or HTTP requests governed by conditional logic (Rules). It provides a programming environment supported by a REST API-based Command Line Interface (CLI) along with tooling to support packaging and catalog services.
OpenWhisk comes with quite a bit of integrations that can be used as triggers or destinations. For example you can listen to Github Webhook or CouchDB change events and then perform certain actions. You can also chain actions if you like. This makes it easy to build IFTTT like services very easy.
IBM Bluemix OpenWhisk
IBM provides a hosted OpenWhisk service called IBM Bluemix OpenWhisk. It’s probably one of the earliest provider of hosted OpenWhisk. You need an IBM id to use it. You don’t need credit card to start using IBM Bluemix services in trial mode. But you need to have a credit card to continue using the services after the trial period. But OpenWhisk has enough freetire allowance that you don’t need to pay for experimentation.
Getting Started
There are two ways to start with OpenWhisk. You can use the UI if the use case or the code is simple. But if the scripts are complex then its better to use CLI. To create a script (or Action in OpenWhisk terminology) using Web UI. Go to Manage under OpenWhisk and click on Create Action. All actions are put under a namespace. UI will prompt to create a namespace if there isn’t one. You can select one if you have already created namespaces.
Give a unique name to the service and select the runtime. I usually code in Python and hence this example is in Python. Swift and Node are the other two options. Also make sure to check Web Action because we want to use it as a web service.
Since it's a simple piece of code. You can test inside the browser.
It’s just three simple steps. Here is the working API endpoint URL that will return your public IP address.
Once echo is working, your setup is ready to do bigger things. To try CLI let’s build a service that will ping the address of a given domain in the parameter. This is not a real ping. Idea here is to show how easy it is to package and deploy serverless applications.
#file name __main__.py import requests def main(args): query_string = args.get('__ow_query',None) if query_string: parameters = {query_string[0] : query_string[1] for query_string in [query_string.split("=") for query_string in query_string.split("&") ]} if "domain" in parameters: domain = parameters["domain"] try: rsp = requests.get(domain) return {"ping":"yes", "domain": str(domain)} except: return {"ping":"no", "domain": str(domain)} return {"error":"Error while pinging"}
To deploy we will create a fabfile that will essentially run the wsk commands which makes it easy to build and deploy in a single step. We use virtualenv to create an isolated environment. Then we install dependencies using requirements package. Then we package it as zip including our main function in a file called __main__.py.
from fabric.api import local action_name = 'ping' def setup(): local('virtualenv virtualenv') local('. virtualenv/bin/activate; pip install -r requirements.txt') def package(): #clean local('rm -rf virtualenv package.zip') #create a zip with all the dependecies local('zip -r package.zip __main__.py virtualenv/') def update(): cmd = 'wsk action update '+action_name+' --kind python:3 package.zip --web raw' local(cmd) def create(): cmd = 'wsk action create '+action_name+' --kind python:3 package.zip --web raw' local(cmd) def delete(): cmd = 'wsk action delete '+action_name local(cmd)
When you run the very first time, you need to create the action and hence use create, from next time onward you can use update. You don't need to run setup unless there are changes in the environment.
#first time thej@uma:~/code/openwhisk-fabfile-deploy$ fab setup package create #for updates thej@uma:~/code/openwhisk-fabfile-deploy$ fab package update
I have all the code on a github repo if you want to fork it and use it.
Hi Thejesh,
I am completely new to this just seeking some guidance from you.
How to build webhook listener? Also we have limitations like 600/min for single actions can be invoked so is their a way that we can queue up all triggers?
If you have any sample please provide.