From a3604bc927778d1bf625b52b72510bc54ec215c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=92scar=20Casajuana?= Date: Wed, 6 Feb 2019 14:55:39 +0100 Subject: [PATCH] Added allowFailure flag to actions closes #35 --- README.md | 22 ++++++++++--- src/model/Action.ts | 14 +++++++- src/worker/ActionExecuter.spec.ts | 54 +++++++++++++++++++++++++++++++ src/worker/ActionExecuter.ts | 6 ++++ 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a18c4f1..fa07e25 100644 --- a/README.md +++ b/README.md @@ -126,19 +126,18 @@ Here's an example of an operator: ~~~yaml # Execute every time a purchase is update -name: someUniqueName +name: some-unique-name-for-this-operator eventName: events.purchase route: updated # true by default, but here you can see you're able to disable them just adding this key. enabled: true -output: "interleaved|group|prefixed" actions: # Print event purchase logs - name: print-log type: log # Type log will use log plugin # Check if event purchase is paid - - name: shouldSendEmail + - name: should-send-email # Type conditional will stop operator execution if some condition is not meet. type: conditional options: @@ -149,7 +148,7 @@ actions: operation: defined # Convert event to email - - name: eventToEmailMapper + - name: map-event-to-email # Type mapper gets the previous action result and converts its fields to a new object with the specified structure. type: mapper options: @@ -163,12 +162,21 @@ actions: '*': vars # Send membership to emails queue applying - - name: sendEventPurchaseToEmailQueue + - name: send-event-purchase-to-email-queue # Type prev2task gets the previous action message and sends it to a task queue. type: prev2task options: target: emails targetRoute: email.send + + # Send a telegram message to a specific group chat + - name: send-telegram-message + type: telegram + # In case the Telegram API fails, ignore the error + allowFailure: true + options: + chatId: '-12345' + template: 'Member with e-mail {{ to }} has registered for event {{ vars.event.name }}' ~~~ ### Available actions to be defined in operators @@ -212,8 +220,11 @@ It checks for defined conditions in the received object and aborts execution if - field: someReceivingObjField operation: === checkValue: valueToCheckAgainst + ~~~ +> **Note:** enabling `allowFailure` here would make the plugin to not work as expected. + ##### Conditional operations - `true` | `isTrue`: Value is set as boolean `true`. @@ -225,6 +236,7 @@ It checks for defined conditions in the received object and aborts execution if - `===`: Variable equals `checkValue`. - `!==`: Variable does not equal `checkValue`. + #### `mapper` It converts the message from the last action executed, to a new object following the specified mapping. diff --git a/src/model/Action.ts b/src/model/Action.ts index a38bfaf..296dc69 100644 --- a/src/model/Action.ts +++ b/src/model/Action.ts @@ -1,14 +1,26 @@ +type ConstructorParams = { + name: string, + type: string, + options: any, + event: string, + allowFailure?: boolean, +} + export default class Action { name: string type: string options: any event: string + allowFailure?: boolean - constructor({name, type, options, event}: {name: string, type: string, options: any, event: string}) { + constructor({name, type, options, event, allowFailure}: ConstructorParams) { this.name = name this.type = type this.options = options this.event = event + if (typeof allowFailure !== 'undefined') { + this.allowFailure = allowFailure + } } toString() { diff --git a/src/worker/ActionExecuter.spec.ts b/src/worker/ActionExecuter.spec.ts index a6a84f2..92eeec0 100644 --- a/src/worker/ActionExecuter.spec.ts +++ b/src/worker/ActionExecuter.spec.ts @@ -1,8 +1,12 @@ +import axios from 'axios' +import axiosMockAdapter from 'axios-mock-adapter' import rabbit from 'rabbot' import ActionExecuter from './ActionExecuter' import Action from '../model/Action' import Event from '../model/Event' +const axiosMock = new axiosMockAdapter(axios) + describe('ActionExecuter', () => { it('should handle comming events', () => { const action = new Action({ @@ -58,4 +62,54 @@ describe('ActionExecuter', () => { return expect(actionExecuter.execute(msg)).resolves.toBeTruthy() }) + + it('should fail on error', () => { + const action = new Action({ + name: 'sendMembershipsToEmail', + type: 'invented', + options: {}, + event: '', + }) + + const actionExecuter = new ActionExecuter(action, rabbit, new Event({ + name: 'test', + eventName: 'test', + route: 'test', + actions: [] + })) + + return expect(actionExecuter.execute({})).rejects.toBeTruthy() + }) + + it('should not fail on error if allowFailure is set to true', () => { + axiosMock.onPost(/api\.telegram\.org/).reply(404) + + const action = new Action({ + name: 'sendMembershipsToEmail', + type: 'telegram', + allowFailure: true, + options: { + chatId: '', + template: '', + }, + event: 'event-name', + }) + + const actionExecuter = new ActionExecuter(action, rabbit, new Event({ + name: 'test', + eventName: 'test', + route: 'test', + actions: [], + })) + + const msg = { + body: { + test: 'Test', + test2: 'Test2', + toString: () => '{test1: "Test", test2: "Test2"}' + } + } + + return expect(actionExecuter.execute(msg)).resolves.toEqual(msg) + }) }) diff --git a/src/worker/ActionExecuter.ts b/src/worker/ActionExecuter.ts index dfaf287..a5f9c7a 100644 --- a/src/worker/ActionExecuter.ts +++ b/src/worker/ActionExecuter.ts @@ -52,6 +52,12 @@ export default class ActionExecuter { return result }) .catch((err) => { + if (this.action.allowFailure) { + logger.info(this.preLog, 'Action execution failed, but allowFailure is set, so ignoring...') + + return Promise.resolve(message) + } + debug('Action executed failed with %j', err) throw err