The Rules Engine Design Pattern


While struggling with the FreeSwitch dialplan language it struck me that I was learning yet another custom approach to a common software use case. FreeSwitch’s dialplan language was addressing the same use case that iptables and Ansible had also addressed. In fact, I suspect this use case applies to most server applications like Apache, postfix, squid, etc. The common use case is simple: receive input data, process this data according to set of rules, then take action based on which rules “fire”.

rules

The problem with the current approach is that each application uses a different implementation of a rules engine, each ones uses custom rules syntax, each one uses custom and often opaque jargon for the same thing, each uses a different way of firing rules, and each supports a unique set of actions. My hypothesis is that this uniqueness is neither necessary nor beneficial.

I think that a better way would be to share a common rules engine that is then customized for each application. It should be based on a core rules engine that is small and very fast. It could be a RETE-based engine written in C. The core engine would have a standard rule syntax, perhaps similar to the one used by CLIPS. You create rules in a text file and load them into the engine. Each time data is received it fires the rules and takes one or more actions.

Each application can customize the rules engine by specifying a set of domain specific objects and properties. iptables would have packet objects, FreeSwitch would have channels, Ansible would have tasks and hosts, and so on. An Ansible rule, for example, might look something like this:

IF
  command.action = update,
  host.location = atlanta,
  host.role = webserver,
  host.os = centos
THEN
  yum.update (host)

A FreeSwitch rule might look like this:

<pre><code>IF
  inbound.DID = 8005551212,
  inbound.callerID = 7035553445
  inbound.sip.realm = "telemarketer.org"
THEN
  transfer.voicemail(inbound)

Admittedly, these examples are only illustrative but I hope you see the idea. The rules engine and syntax stay the same only the domain objects change. The benefit is that administrators only have one rules paradigm to learn. The current morass of config file formats—XML for FreeSwitch, YML for Ansible, Ruby for Chef, ini files, etc.—makes them unnecessarily hard to learn and maintain. Most don’t even have a way to validate the config file before loading it. The common rules engine could have this critical feature syntax checking feature.

The other big benefit is that people could develop standard plugins (modules) that could be used by the all applications. These plugins would add new actions for the rules to take when they fire. For example, a plugin to send log data to syslog, email a notification, send a message via XMPP, send data to SNMP, send output to HTTP, call an API, etc. One syslog plugin usable by all the applications instead of 20 different ways of doing the exact same thing now. Each domain object and plugin adds to the capabilities and semantic richness of the common engine.

Real configuration data such as what NIC a server should listen on can be stored as “facts” by the engine (to use a CLIPS term). Facts could model the installation-unique properties, and can also be processed by the rules. The Ansible host data is an example of data that could be modeled as facts.

So, in summary, the common rules engine approach requires:

  • A fast and extensible common rules engine
  • Application specific data modeled as objects with properties within the rules engine
  • Site configuration is model as facts (object assigned predetermined property values and loaded with the engine)
  • Custom plugins extend the actions that the engine supports
  • Data enters the engine as an object (SIP call received, command issued, web GET received, email arrives, etc)
  • Engine rules fire when data is received
  • Engine takes actions including sending data to another engine making a very cool pipe and filter architecture

pipe-filterI realize there are issues with this approach. It may not be fast enough for iptables but I am sure it would be for most other applications. The re-usability would be impressive if we could overcome the Barney Fallacy (“my application is special”).



Categories: Software

Tags:

Share Your Ideas

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: