Esempio n. 1
0
    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'],
        )
Esempio n. 2
0
    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
Esempio n. 3
0
    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,
            }])
        ]
Esempio n. 4
0
    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
Esempio n. 5
0
    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)