def recover_step(self, message: dict): ''' given an execution id and a pointer from the persistent storage, return the asociated process node to continue its execution ''' try: pointer = Pointer.get_or_exception(message['pointer_id']) if pointer.status != 'ongoing': raise ModelNotFoundError( 'Specified pointer never existed, and never will', ) except ModelNotFoundError: raise InconsistentState('Queued dead pointer') user = User.get_by('identifier', message.get('user_identifier')) if user is None: if message.get('user_identifier') == '__system__': user = User(identifier='__system__', fullname='System').save() else: raise InconsistentState('sent identifier of unexisten user') return ( pointer, user, message['input'], )
def notify_users(self, node, pointer, channel, state): node_state = state['state']['items'][node.id] if node_state['state'] == 'invalid': users = self.get_invalid_users(node_state) else: users = node.get_actors(self.config, state) if type(users) != list: raise MisconfiguredProvider('Provider returned non list') if len(users) == 0: raise InconsistentState( 'No user assigned, dead execution {}'.format( pointer.proxy.execution.get().id, ) ) channel.exchange_declare( exchange=self.config['RABBIT_NOTIFY_EXCHANGE'], exchange_type='direct' ) notified_users = [] for user in users: notified_users.append(user.to_json()) user.proxy.tasks.add(pointer) mediums = self.get_contact_channels(user) for medium, params in mediums: channel.basic_publish( exchange=self.config['RABBIT_NOTIFY_EXCHANGE'], routing_key=medium, body=json.dumps({**{ 'data': { 'pointer': pointer.to_json( include=['*', 'execution'] ), 'cacahuate_url': self.config['GUI_URL'], }, }, **params}), properties=pika.BasicProperties( delivery_mode=2, ), ) LOGGER.debug('Waking up n:{} found users: {} e:{}'.format( node.id, ', '.join(u.identifier for u in users), pointer.proxy.execution.get().id, )) return notified_users
def work(self, config, state, channel, mongo): tree = Condition().parse(self.condition) try: value = ConditionTransformer(state['values']).transform(tree) except ValueError as e: raise InconsistentState('Could not evaluate condition: {}'.format( str(e))) return [ Form.state_json(self.id, [{ 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': value, }]) ]
def notify_users(self, node, pointer, state): node_state = state['state']['items'][node.id] if node_state['state'] == 'invalid': users = self.get_invalid_users(node_state) else: users = node.get_actors(self.config, state) if type(users) != list: raise MisconfiguredProvider('Provider returned non list') if len(users) == 0: raise InconsistentState( 'No user assigned, dead execution {}'.format( pointer.execution.get().id, )) notified_users = [] for user in users: notified_users.append(user.to_json()) user.tasks.add(pointer) mediums = self.get_contact_channels(user) for medium, params in mediums: self.send_notify( json.dumps({ **{ 'data': { 'pointer': pointer.to_json(include=['*', 'execution']), 'cacahuate_url': self.config['GUI_URL'], }, }, **params }), medium) LOGGER.debug('Waking up n:{} found users: {} e:{}'.format( node.id, ', '.join(u.identifier for u in users), pointer.execution.get().id, )) return notified_users
def patch(self, message): execution = Execution.get_or_exception(message['execution_id']) if execution.status != 'ongoing': raise ModelNotFoundError( 'Specified execution never existed, and never will', ) xml = Xml.load(self.config, execution.process_name, direct=True) # set nodes with pointers as unfilled, delete pointers updates = {} user = User.get_by( 'identifier', message.get('user_identifier'), ) if user is None: if message.get('user_identifier') == '__system__': user = User(identifier='__system__', fullname='System').save() else: raise InconsistentState('sent identifier of unexisten user') for pointer in execution.pointers.q().filter(status='ongoing'): updates['state.items.{node}.state'.format( node=pointer.node_id, )] = 'unfilled' pointer.status = 'cancelled' pointer.finished_at = datetime.now() pointer.save() self.pointer_collection().update_one({ 'id': pointer.id, }, { '$set': { 'state': 'cancelled', 'finished_at': pointer.finished_at, 'patch': { 'comment': message['comment'], 'inputs': message['inputs'], 'actor': user.to_json(include=[ '_type', 'fullname', 'identifier', ]), }, }, }) self.execution_collection().update_one({ 'id': execution.id, }, { '$set': updates, }) # retrieve updated state state = next(self.execution_collection().find({'id': execution.id})) state_updates, array_filters = cascade_invalidate( xml, state, message['inputs'], message['comment']) # update state self.execution_collection().update_one( {'id': state['id']}, {'$set': state_updates}, array_filters=array_filters, ) # retrieve updated state state = next(self.execution_collection().find({'id': execution.id})) first_invalid_node = track_next_node(xml, state, self.get_mongo(), self.config) # wakeup and start execution from the found invalid node self.wakeup_and_notify(first_invalid_node, execution, state)