2020-11-08 - Activity Switchboard - Functions

From Izara Wiki
Jump to navigation Jump to search

Service - Activity Switchboard

Lambda Functions

receiveMsg

/**
 * Receives messages from project's In and Out topics
 * @param {Object} topicArn - topicArn for the received message
 * @param {Object} attributes - message attributes from the received message
 * @param {Object} message - received message object
 *
 * @returns {string} sortResultId
 */

HdrSqs

Subscribes to In and Out topics for any number of services, one msgCfg per one topic subscription

handler logic

Pulls topicArn and message attribute data from request and places into attributes object

logic

  1. use NPM module - izara-shared#AwsSharedLib.GetResourceNameFromArn to get topicName
  2. find msgCfg using #getMsgCfg
  3. if not found
    1. warning error
    2. return
  4. if msgCfg.activitySwitchboard != true
    1. warning error
    2. return
  5. set var checkedProperties to empty array
      1. invoke #checkTriggers for serviceName
      2. invoke #checkTriggers for topicName
  6. invoke #recursiveCheckProperties passing in msgCfg (accumulatePropertyName = "property")
  7. for each msgCfg.messageAttributes as messageAttribute
    1. if messageAttribute.activityTrigger = true
      1. invoke #checkTriggers
      2. add messageAttribute name to checkedProperties (concatenate "attribute." + msgCfg.messageAttributes index)

updateMsgCfg

/**
 * Is triggered by updates on Message Config Manager service, updates local record.
 * @param {string} serviceName - message attributes from the received message
 * @param {string} topicName
 * @param {Object} msgCfg
 * @param {string} action - "add"|"update"|"delete"
 */

HdrSqs

Subscribes to Service - Message Config Manager OutXXX topic

logic

  • message from Message Config Manager includes a timestamp that we can use to ensure the msgCfg has the most recent setting saved
  • lib shared handling of message logic with pullMsgCfg
  • if record not exist in Config create it
  1. if action is "add" or "update", insert/update "msgCfg" record in Config table
  2. if action is "delete" change configValue in Config table to :

update 2021-05-10

  • need to get old record from Dynamo
  • if old record not exist or changing from activitySwitchboard = false to true, then we also need to create ReceiveMsg subscription
  • if old record is true and deleting or changing from activitySwitchboard = true to false, need to delete ReceiveMsg subscription

removeTriggerGroup

/**
 * Removes trigger group and all it's triggers
 * @param {string} receiverTag
 * @param {string} uniqueId
 *
 */

HdrSqs

Subscribes to InRemoveTriggerGroup topic

logic

  1. create triggerGroupId using #createTriggerGroupId
  2. get from TriggerGroups table matching record, in variable triggerGroup
  3. if no records found log warning and return
  4. for each triggerGroup.triggers
    1. delete from Triggers table
  5. send message to OutTriggerGroupRemoved topic, can include full triggerGroup object

CreateTriggerGroup

/**
 * Creates one trigger group and all triggers
 * @param {string} receiverTag
 * @param {string} uniqueId
 * @param {Object[]} [additionalData]
 * @param {Object[]} triggers
 * @param {string} triggers.propertyName
 * @param {string} triggers.valueType - property|attribute
 * @param {string} [triggers.value] - either value or values will be set
 * @param {string[]} [triggers.values] - either value or values will be set
 *
 */

HdrSqs

Subscribes to InCreateTriggerGroup topic

Validator:

  • triggerGroupId cannot be empty string

logic

  1. create triggerGroupId using #createTriggerGroupId
  2. put into TriggerGroups table
  3. (if put returns that there is an existing record with same triggerGroupId we don't stop in case this result failed half way through processing and is being retried)
  4. for each triggers as trigger:
    1. create an array variable triggerValues
    2. if triggers.value is set add its value as an element in triggerValues
    3. else if triggers.values is set and is an array copy its elements into triggerValues
    4. else:
      1. send message to OutCreateTriggerFailed topic, include triggerGroupId, additionalData, trigger and error property = "Trigger object does include any value"
      2. return
    5. if trigger.propertyName is empty string:
      1. send message to OutCreateTriggerFailed topic, include triggerGroupId, additionalData, trigger and error property = "Trigger object does include propertyName"
      2. return
    6. if trigger.valueType != "property"|"attribute":
      1. send message to OutCreateTriggerFailed topic, include triggerGroupId, additionalData, trigger and error property = "Trigger object valueType invalid"
      2. return
    7. for each triggerValues:
      1. create triggerId from #createTriggerId
      2. put into Triggers table
  5. send message to OutTriggerGroupCreated topic, can include full triggerGroup object

Functions

createTriggerGroupId

/**
 * Creates triggerGroupId id
 * @param {string} receiverTag
 * @param {string} uniqueId
 *
 * @returns {string} triggerGroupId
 */

logic

  1. return conatenate {receiverTag} + "_" + {uniqueId}

explodeTriggerGroupId

/**
 * pulls out elements from a triggerGroupId
 * @param {string} triggerGroupId
 *
 * @returns {string[]} first element is receiverTag, second is uniqueId
 */

logic

  1. return explode triggerGroupId using "_"

createTriggerId

/**
 * Creates trigger id
 * @param {string} propertyName
 * @param {string} propertyValue
 *
 * @returns {string} triggerId
 */

logic

  1. hash propertyName
  2. hash propertyValue
  3. return concatenate {hash of propertyName} + "_" + {hash of propertyValue}

explodePropertyName

/**
 * pulls out elements from a propertyName
 * @param {string} propertyName
 *
 * @returns {string[]} first element is the valueType, if property remaining elements are an array of nested property location, if attribute is the attributes name
 */

logic

  1. explode propertyName using "." put into variable elements
  2. let property = {valueType = elements[0]};
  3. if property.valueType == "attribute"
    1. property.propertyName = elements[1]
  4. else if property.valueType == "property"
    1. property.propertyName = elements
    2. property.propertyName.shift(); // removes first element
  5. else
    1. throw error
  6. return property

getMsgCfg

/**
 * Queries Config table to find MsgCfg
 * @param {string} serviceName
 * @param {string} topicName
 *
 * @returns {Object} msgCfg
 */

logic

  1. msgCfgId = NPM module - izara-shared#MsgCfgLib.CreateMsgConfigId
  2. Query Config table for configKey = "MsgCfg", configTag = msgCfgId
  3. return found msgCfg or false if none found

recursiveCheckProperties

/**
 * iterates one level of properties and checks matching activities for each
 * @param {Object} msgCfgPropertiesOneLevel
 * @param {Object} messageOneLevel
 * @param {number} level
 * @param {string} accumulatePropertyName - is a string that concatenates where this property within nested structure
 * @param {string[]} checkedProperties
 * @param {Object} attributes - needed to pass on to checkTriggers
 * @param {Object} message - needed to pass on to checkTriggers
 * @param {string} serviceName - needed to pass on to checkTriggers
 * @param {string} topicName - needed to pass on to checkTriggers
 *
 * @returns {string[]} checkedProperties - so can accumulate full list of checkedProperties
*/
recursiveCheckProperties = (msgCfgPropertiesOneLevel, messageOneLevel, level, accumulatePropertyName, checkedProperties, attributes, message) => {

logic

  1. ... standard level check, see Tam's work
  2. if !msgCfgPropertiesOneLevel.properties return
  3. for each msgCfgPropertiesOneLevel.properties as property
    1. if property.activityTrigger = true
      1. invoke #checkTriggers
      2. add property name to checkedProperties (concatenate accumulatePropertyName + "." + property.propertyName)
    2. else if property.isObject = true
      1. invoke #recursiveCheckProperties passing in property variable (accumulatePropertyName = accumulatePropertyName + "." + property.propertyName)

checkTriggers

/**
 * Finds all matching triggers, tests whether trigger group matches, if match send message to Out topic
 * @param {string} propertyName - is the full nested location of the property including valueType
 * @param {string} propertyValue
 * @param {string[]} checkedProperties
 * @param {Object} attributes
 * @param {Object} message
 * @param {string} serviceName
 * @param {string} topicName
 */

logic

  1. use #createTriggerId to create trigger id
  2. query #Triggers table to find all matching triggers
  3. for each trigger found
    1. query #TriggerGroup table for trigger.triggerGroupId
    2. for each triggerGroup.triggers as testTrigger
      1. if already exists in checkedProperties continue to next TriggerGroup
      2. (if any testTrigger for a triggerGroup has already been checked (added to checkedProperties) then we know that triggerGroup has already been processed for this message)
    3. for each triggerGroup.triggers as testTrigger
      1. (second loop to test all other triggers in this triggerGroup pass?)
      2. use #explodePropertyName to get property object
      3. use property.valueType to compare testTrigger.propertyValue against attributes / message / serviceName / topicName, check if this property.propertyName exists and if its value matches testTrigger.propertyValue
      4. if not match continue to next triggerGroup
    4. to arrive here all triggerGroup.triggers passed, so we have a triggerGroup that matches the received message
    5. extract receiverTag and uniqueId from triggerGroup.triggerGroupId using #explodeTriggerGroupId
    6. send message to OutTriggerGroupPassed topic, adding below properties:
      1. receiverTag gets added to message attributes so can be filtered for by receiving service
      2. add attributes, message
      3. uniqueID
      4. triggerGroup.additionalData

update 2021-05-10

  • if multiple values are sent for one property, this becomes an "or" check, any value can pass
  • to achieve this in our first loop of testTriggers we create a counter object for each propertyname (includes valueType)
  • the value for the counter matches how many testTriggers for that propertyname
  • when checking testTrigger matches message, if it matches do not decrease this counter, this ensures it will never count down and skip that triggerGroup
  • each testTrigger that does not match reduces counter by 1, and checks the counter to see if it is the last testTrigger, if yes means no testTriggers match for that propertyname and can skip the triggerGroup

Sample activityMsg sent to receiver service

{
	topicName: zzz
	activityMsg: {
		messageAttributes: {
			// xxx: yyy
		},
		message: {
			// full body of message received
		}
	},
	additionalData: {
		notificationId: aaa_bbb_ccc
	},
	time: {timestamp processed at Activity Switchboard}
}