├── .gitignore ├── .npmignore ├── index.js ├── package.json ├── example.js ├── LICENSE ├── skej └── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | redular.js 2 | test.js 3 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./skej'); 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "skej", 3 | "version": "0.0.3", 4 | "description": "OpenFaaS function scheduler, backed by Redis", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Austin Frey", 10 | "license": "MIT", 11 | "dependencies": { 12 | "bluebird": "^3.5.0", 13 | "redular": "^1.2.0", 14 | "openfaas": "0.0.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const skej = require('./index'); 4 | 5 | skej({ 6 | 7 | single: [ 8 | { 9 | name: 'func_nodeinfo', 10 | initialRun: 5, 11 | onFinished: x => console.log('func_nodeinfo:', x.body) 12 | }, 13 | { 14 | name: 'func_echoit', 15 | data: 'hello world', 16 | initialRun: 2, 17 | recurring: 1, 18 | onFinished: x => console.log('func_echoit:', x.body) 19 | }, 20 | { 21 | name: 'foo', 22 | json: true, 23 | initialRun: 1, 24 | recurring: 10, 25 | onFinished: x => console.log('foo:\n', x.body) 26 | } 27 | ], 28 | 29 | pipe: [ 30 | { 31 | name: 'test', 32 | data: '', 33 | initialRun: 8, 34 | pipeline: [ 35 | 'func_nodeinfo', 36 | 'func_wordcount' 37 | ], 38 | onFinished: x => console.log('Piped Function Wordcount:\n', x.body) 39 | }, 40 | ] 41 | // gateway URL is optional and defaults to http://localhost:8080 42 | // if one is not supplied 43 | }, 'http://45.45.45.45:8080'); 44 | 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /skej/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const FaaS = require('openfaas'); 4 | const Redular = require('redular'); 5 | const BbPromise = require('bluebird'); 6 | 7 | const skej = (schedule, url = 'http://localhost:8080') => { 8 | const {invoke, compose} = FaaS(url); 9 | const {single, pipe} = schedule; 10 | const options = { 11 | autoconfig: true, 12 | redis: { 13 | port: 6379, 14 | host: 'localhost' 15 | } 16 | }; 17 | 18 | const redular = new Redular(options); 19 | 20 | const invokeFuncs = list => { 21 | return new BbPromise.each(list, func => { 22 | const date = new Date(); 23 | let noop = () => {} 24 | 25 | func.hasOwnProperty('recurring') ? 26 | noop = () => { 27 | const newDate = new Date(); 28 | newDate.setSeconds(newDate.getSeconds() + func.recurring); 29 | redular.scheduleEvent(func.name, newDate); 30 | } : 31 | noop 32 | 33 | redular.defineHandler(func.name, () => { 34 | invoke(func.name, func.data) 35 | .then(func.onFinished) 36 | .then(noop) 37 | .catch(err => console.log(err)); 38 | }); 39 | 40 | redular.scheduleEvent( 41 | func.name, 42 | date.setSeconds(date.getSeconds() + func.initialRun) 43 | ); 44 | }); 45 | }; 46 | 47 | const scheduleSingles = list => { 48 | invokeFuncs(list) 49 | .then(() => console.log('scheduled')) 50 | .catch(err => console.log(err)); 51 | }; 52 | 53 | const schedulePipes = list => { 54 | const date = new Date(); 55 | 56 | list.forEach(pipe => { 57 | redular.defineHandler(pipe.name, () => { 58 | compose(pipe.data, pipe.pipeline) 59 | .then(pipe.onFinished) 60 | .catch(err => console.log(err)); 61 | }); 62 | 63 | redular.scheduleEvent( 64 | pipe.name, 65 | date.setSeconds(date.getSeconds() + pipe.initialRun) 66 | ); 67 | }); 68 | }; 69 | 70 | scheduleSingles(single); 71 | schedulePipes(pipe); 72 | 73 | console.log('starting'); 74 | }; 75 | 76 | module.exports = skej; 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![OpenFaaS](https://img.shields.io/badge/openfaas-serverless-blue.svg) 2 | 3 | ## skej 4 | 5 | #### a simple event schedular for OpenFaaS 6 | 7 | Skej allows you to declaratively schedule events for OpenFaaS functions. 8 | 9 | #### How To 10 | 11 | ###### Prerequisites 12 | Requires NodeJS version 6.4.0 and up. 13 | 14 | Redis should be running on port 6379. This is easy to do with docker 15 | ``` 16 | docker run -d -p 6379:6379 redis 17 | ``` 18 | 19 | `skej` will try to autoconfigure redis to support expiring keys, but you may need to use `redis-cli` if it doesn't cooperate. 20 | ``` 21 | $ redis-cli 22 | > config set notify-keyspace-events Ex 23 | ``` 24 | 25 | ###### Install 26 | ``` 27 | $ npm install skej 28 | ``` 29 | 30 | ###### Import skej 31 | 32 | ``` 33 | const skej = require('skej') 34 | ``` 35 | 36 | ###### Write the schedule 37 | Declare your schedule as a JSON object. 38 | 39 | There are two types of scheduled functions `single` and `pipe`. 40 | One off and recurring functions would fall under `single` and can be 41 | scheduled like so. 42 | ``` 43 | // index.js 44 | const schedule = { 45 | single: [ 46 | { 47 | name: 'func_nodeinfo', 48 | initialRun: 5, 49 | onFinished: x => console.log(x.body) 50 | }, 51 | { 52 | name: 'func_echoit', 53 | data: 'hello world', 54 | initialRun: 2, 55 | recurring: 10, 56 | onFinished: x => console.log(x.body) 57 | }, 58 | ], 59 | } 60 | ``` 61 | Notice that the `func_echoit` function has an addition property, 62 | `recurring`. If the function should run more than once, at a regular 63 | interval, set the recurring flag to the appropriate duration in seconds. 64 | `skej` will handle the rest. 65 | 66 | Adding a chain of functions requires grouping functions as `pipe` 67 | functions. Give the 'pipeline' a name, include and initial data that 68 | should be passed to the first function, and list the function names under 69 | `pipeline` 70 | ``` 71 | // index.js 72 | ... 73 | pipe: [ 74 | { 75 | name: 'test', 76 | data: '', 77 | initialRun: 8, 78 | pipeline: [ 79 | 'func_nodeinfo', 80 | 'func_wordcount' 81 | ], 82 | onFinished: x => console.log(x.body) 83 | } 84 | ] 85 | } 86 | 87 | /* 88 | wrap schedule in the skej() function 89 | and include the OpenFaaS gateway URL, defaults to http://localhost:8080 90 | if no URL is supplied 91 | */ 92 | skej(schedule, 'http://11.11.11.11:8080') 93 | ``` 94 | See the `example.js` file for the completed description. 95 | 96 | ###### Launching 97 | ``` 98 | node index.js 99 | ``` 100 | 101 | ###### ToDo 102 | * Remove hardcoded gateway URL 103 | * Ability to schedule to same function multiple times, name and 104 | function name should be seperate properties 105 | 106 | 107 | ###### Additional 108 | Give it a try and please submit issues as you have them. 109 | 110 | --------------------------------------------------------------------------------