{"id":20331146,"url":"https://github.com/comcast/rulio","last_synced_at":"2025-04-06T00:10:01.443Z","repository":{"id":48829182,"uuid":"46152165","full_name":"Comcast/rulio","owner":"Comcast","description":"Rulio","archived":false,"fork":false,"pushed_at":"2023-02-25T06:19:04.000Z","size":701,"stargazers_count":336,"open_issues_count":28,"forks_count":59,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-03-29T23:09:07.814Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Comcast.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-11-13T23:13:00.000Z","updated_at":"2025-03-21T15:16:43.000Z","dependencies_parsed_at":"2024-06-18T20:09:56.641Z","dependency_job_id":"b06b3bf2-3cf1-4996-92cf-4a8a365ce5e7","html_url":"https://github.com/Comcast/rulio","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comcast%2Frulio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comcast%2Frulio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comcast%2Frulio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comcast%2Frulio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Comcast","download_url":"https://codeload.github.com/Comcast/rulio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247415972,"owners_count":20935387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T20:18:57.060Z","updated_at":"2025-04-06T00:10:01.428Z","avatar_url":"https://github.com/Comcast.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n\nCopyright 2015 Comcast Cable Communications Management, LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nEnd Copyright --\u003e\n\n[![Build Status](https://travis-ci.org/Comcast/rulio.svg)](https://travis-ci.org/Comcast/rulio)\n\n\n![Rulio is a rules engine](https://raw.githubusercontent.com/Comcast/rulio/master/doc/Rulio_logo_400x124.png)\n\n## Overview\n\nA rules engine.  You write rules and send events.  You can also write\nsome facts that rules can use.  When an event arrives, the system\nfinds candidate rules.  A candidate rule's condition is evaluated to\nfind zero or more sets of variable bindings.  For each set of variable\nbindings, the rule's actions are executed.\n\nSee the [docs](doc) for more.  In particular, see `doc/Manual.md`.\nThere are lots of examples in `examples/`.\n\nAlso see [`Comcast/sheens`](https://github.com/Comcast/sheens).\n\n## License\n\nThis software is released under the Apache License, Version 2.0.  See\n`LICENSE` in this repo.\n\n\n## Usage\n\n### Starting\n\nTo compile, you need [Go](https://golang.org/).  Then\n\n```Shell\n(cd rulesys \u0026\u0026 go get . \u0026\u0026 go install)\nbin/startengine.sh \u0026\nENDPOINT=http://localhost:8001\nLOCATION=here\ncurl -s $ENDPOINT/version\n```\n\nIf you see some JSON, the engine is probably running.  Check\n`engine.log` to see some logging.\n\n\n### A simple rule\n\nNow let's use that engine.  In these examples, we'll talk to the\nengine using its primitive HTTP API.\n\n```Shell\n# Write a fact.\ncurl -s -d 'fact={\"have\":\"tacos\"}' \"$ENDPOINT/api/loc/facts/add?location=$LOCATION\"\n\n# Query for the fun of it.\ncurl -s -d 'pattern={\"have\":\"?x\"}' \"$ENDPOINT/api/loc/facts/search?location=$LOCATION\" | \\\n  python -mjson.tool\n\n# Write a simple rule.\ncat \u003c\u003cEOF | curl -s -d \"@-\" \"$ENDPOINT/api/loc/rules/add?location=$LOCATION\"\n{\"rule\": {\"when\":{\"pattern\":{\"wants\":\"?x\"}},\n          \"condition\":{\"pattern\":{\"have\":\"?x\"}},\n          \"action\":{\"code\":\"var msg = 'eat ' + x; console.log(msg); msg;\"}}}\nEOF\n\n# Send an event.\ncurl -d 'event={\"wants\":\"tacos\"}' \"$ENDPOINT/api/loc/events/ingest?location=$LOCATION\" | \\\n   python -mjson.tool\n```\n\nThe `events/ingest` output is pretty big.  This data contains\nsufficient information to enable you to reattempt/resume event\nprocessing in the case the engine encountered one or more errors\nduring the previous processing.\n\n\n### Scheduled rule\n\nNow let's write a little scheduled rule.\n\n```Shell\n# First a quick check to see if a Javascript action can give us a timestamp.\ncurl -d 'code=new Date().toISOString()' $ENDPOINT/api/sys/util/js\n\n# Write a scheduled rule.\ncat \u003c\u003cEOF | curl -s -d \"@-\" \"$ENDPOINT/api/loc/rules/add?location=$LOCATION\"\n{\"rule\": {\"schedule\":\"+3s\",\n          \"condition\":{\"pattern\":{\"have\":\"?x\"}},\n          \"action\":{\"code\":\"console.log('eating ' + x + ' at ' + (new Date().toISOString()) + '.');\"}}}\nEOF\n```\n\nLook for a line starting with `eating tacos` in the engine output.\n\n```Shell\ngrep -F 'eating tacos' engine.log\n```\n\nThat rule runs only once.  Three seconds from when it was created.\n(We can also use full cron syntax to specify a repeating schedule.)\n\n\n### Action talking to an external service\n\nNow let's make a rule with an action that talks to an external\nservice.  We'll start a dummy service that just prints out what it\nhears.\n\n```Shell\n# Start our dummy service.  Use another window.\n(cd examples \u0026\u0026 ./endpoint.py) \u0026\n\n# See if it works.\ncurl \"http://localhost:6668/foo?likes=tacos\"\n# Should see some data in that service's window.\n\n# Write the rule.  This rule has no condition.\ncat \u003c\u003cEOF | curl -s -d \"@-\" \"$ENDPOINT/api/loc/rules/add?location=$LOCATION\"\n{\"rule\": {\"when\":{\"pattern\":{\"wants\":\"?x\"}},\n          \"action\":{\"code\":\"Env.http('GET','http://localhost:6668/do?order=' + Env.encode(x))\"}}}\nEOF\n\n# Send an event.  Should trigger that action.\ncurl -d 'event={\"wants\":\"Higher Math\"}' \"$ENDPOINT/api/loc/events/ingest?location=$LOCATION\" | \\\n   python -mjson.tool\n# You should see an order in the `endpoint.py' output.\n```\n\n\n### Rule condition querying an external service\n\nThe rules engine can query external services during rule condition\nevaluation.  Such a service is called an \"external fact service\".  We\nhave a few example fact services in `examples/`.  Here's one that can\nreport the weather.\n\n```Shell\n(cd examples \u0026\u0026 ./weatherfs.py) \u0026\n\n# Test it.\ncurl -d '{\"locale\":\"Austin,TX\",\"temp\":\"?x\"}' 'http://localhost:6666/facts/search'\n\n# Write a rule that uses that source of facts.\ncat \u003c\u003cEOF | curl -s -d \"@-\" \"$ENDPOINT/api/loc/rules/add?location=$LOCATION\"\n{\"rule\": {\"when\":{\"pattern\":{\"visitor\":\"?who\"}, \"location\":\"here\"},\n          \"condition\":{\"and\":[{\"pattern\":{\"locale\":\"Austin,TX\",\"temp\":\"?temp\"},\n                               \"locations\":[\"http://localhost:6666/facts/search\"]},\n                              {\"code\":\"console.log('temp: ' + temp); 0 \u003c temp\"}]},\n          \"action\":{\"code\":\"Env.http('GET','http://localhost:6668/report?weather=' + Env.encode('warm enough'))\"}}}\nEOF\n\n# Send an event.  Should trigger that action.\ncurl -d 'event={\"visitor\":\"Homer\"}' \"$ENDPOINT/api/loc/events/ingest?location=$LOCATION\" | \\\n   python -mjson.tool\n```\n\n### Javascript libraries\n\nLet's use a library of Javascript code in a rule action.\n\n```Shell\n# Start a library server.\n(cd examples \u0026\u0026 ./libraries.py) \u0026\n\n# Check that we can get a library.\ncurl http://localhost:6669/libs/tester.js\n\ncurl \"$ENDPOINT/api/loc/admin/clear?location=$LOCATION\"\n\n# Write the rule.\ncat \u003c\u003cEOF | curl -d \"@-\" \"$ENDPOINT/api/loc/rules/add?location=$LOCATION\"\n{\"rule\": {\"when\":{\"pattern\":{\"wants\":\"?x\"}},\n          \"condition\":{\"code\":\"isGood(x)\",\n                       \"libraries\":[\"http://localhost:6669/libs/tester.js\"]},\n          \"action\":{\"code\":\"var msg = 'Serve ' + x + ' ('+ isGood(x) + ')'; console.log(msg); msg;\",\n                    \"opts\":{\"libraries\":[\"http://localhost:6669/libs/tester.js\"]}}}}\nEOF\n\n# Send an event.  Should trigger that action.\ncurl -d 'event={\"wants\":\"Higher Math\"}' \"$ENDPOINT/api/loc/events/ingest?location=$LOCATION\" | \\\n   python -mjson.tool\n\n# Send another event.  Should not trigger that action.\ncurl -d 'event={\"wants\":\"Duff Light\"}' \"$ENDPOINT/api/loc/events/ingest?location=$LOCATION\" | \\\n   python -mjson.tool\n```\n\nYou can also use libraries in Javascript rule actions.\n\nYour libraries can be pretty fancy (see `example/libs/haversine.js`),\nbut be cautious about efficiency and robustness.  If you find yourself\nwanting to do a lot of work in action Javascript, think about writing\nan action executor instead.\n\n\n### Action executors\n\nIf you don't want to write your actions in Javascript, which runs\ninside the rules engine, you can use *action executors*.  An action\nexecutor is an external service that is given rule actions to execute.\nIn a serious deployment, an action executor endpoint would probably\njust queue those actions for a pool of workers to process.\n\nAn action executor can do or execute anything in any language or\nspecification.  Up to the author of the executor.\n\nWe have an example action executor in Python in `examples/executor.py`.\n\n```Shell\n# Run the toy action executor.\n(cd examples \u0026\u0026 ./executor.py) \u0026\n\ncat \u003c\u003cEOF | curl -s -d \"@-\" \"$ENDPOINT/api/loc/rules/add?location=$LOCATION\"\n{\"rule\":{\"when\":{\"pattern\":{\"drinks\":\"?x\"}},\n         \"action\":{\"endpoint\":\"http://localhost:8081/execbash\",\n                   \"code\":{\"order\":\"?x\"}}}}\nEOF\n\n# Send an event.\ncurl -d 'event={\"drinks\":\"milk\"}' \"$ENDPOINT/api/loc/events/ingest?location=$LOCATION\" | \\\n  python -mjson.tool\n```\n\nThat event should generate a request to the example action executor,\nwhich doesn't actually do anything.\n\nYou can also write your own _action interpreters_.  For example, you\ncould write an interpreter (shim) for Bash script actions and really\ncause some trouble.\n\n\n### Getting some statistics\n\nFinally, let's get some statistics.\n\n```Shell\ncurl -s \"$ENDPOINT/api/loc/admin/stats?location=$LOCATION\" | python -mjson.tool\ncurl -s \"$ENDPOINT/api/sys/stats\" | python -mjson.tool\n```\n\n### APIs\n\nThe engine is designed in packages.  The core is in\n[`core/`](https://godoc.org/github.com/Comcast/rulio/core), and\n[`sys/`](https://godoc.org/github.com/Comcast/rulio/sys) provides\nsomething like a container for locations.\n\nThe network API used above and provided by `service/` is rendered in\nHTTP, but it was originally designed for message-oriented transports.\nFor example, all requests are handled by `service.ProcessRequest()`,\nwhich is (mostly) independent of transport.\n\nPersistence is mostly pluggable.  See `storage/` for examples.\n\n\n## Conclusion\n\nTake a look at the `doc/Manual.md` for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomcast%2Frulio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcomcast%2Frulio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomcast%2Frulio/lists"}