Пример #1
0
async def run_activity(
    *,
    lifecycle: lifecycles.LifeCycleFn,
    registry: registries.OperatorRegistry,
    settings: configuration.OperatorSettings,
    activity: handlers_.Activity,
    indices: ephemera.Indices,
    memo: ephemera.AnyMemo,
) -> Mapping[ids.HandlerId, callbacks.Result]:
    logger = logging.getLogger(f'kopf.activities.{activity.value}')

    # For the activity handlers, we have neither bodies, nor patches, just the state.
    cause = causation.ActivityCause(
        logger=logger,
        activity=activity,
        settings=settings,
        indices=indices,
        memo=memo,
    )
    handlers = registry._activities.get_handlers(activity=activity)
    state = states.State.from_scratch().with_handlers(handlers)
    outcomes: MutableMapping[ids.HandlerId, states.HandlerOutcome] = {}
    while not state.done:
        current_outcomes = await handling.execute_handlers_once(
            lifecycle=lifecycle,
            settings=settings,
            handlers=handlers,
            cause=cause,
            state=state,
        )
        outcomes.update(current_outcomes)
        state = state.with_outcomes(current_outcomes)
        await primitives.sleep_or_wait(state.delay)

    # Activities assume that all handlers must eventually succeed.
    # We raise from the 1st exception only: just to have something real in the tracebacks.
    # For multiple handlers' errors, the logs should be investigated instead.
    exceptions = [
        outcome.exception for outcome in outcomes.values()
        if outcome.exception is not None
    ]
    if exceptions:
        raise ActivityError("One or more handlers failed.",
                            outcomes=outcomes) from exceptions[0]

    # If nothing has failed, we return identifiable results. The outcomes/states are internal.
    # The order of results is not guaranteed (the handlers can succeed on one of the retries).
    results = {
        handler_id: outcome.result
        for handler_id, outcome in outcomes.items()
        if outcome.result is not None
    }
    return results
Пример #2
0
async def activity_trigger(
    *,
    lifecycle: lifecycles.LifeCycleFn,
    registry: registries.OperatorRegistry,
    activity: causation.Activity,
) -> Mapping[registries.HandlerId, registries.HandlerResult]:
    """
    Execute a handling cycle until succeeded or permanently failed.

    This mimics the behaviour of patching-watching in Kubernetes, but in-memory.
    """
    logger = logging.getLogger(f'kopf.activities.{activity.value}')

    # For the activity handlers, we have neither bodies, nor patches, just the state.
    cause = causation.ActivityCause(logger=logger, activity=activity)
    handlers = registry.get_activity_handlers(activity=activity)
    state = states.State.from_scratch(handlers=handlers)
    latest_outcomes: MutableMapping[registries.HandlerId,
                                    states.HandlerOutcome] = {}
    while not state.done:
        outcomes = await _execute_handlers(
            lifecycle=lifecycle,
            handlers=handlers,
            cause=cause,
            state=state,
        )
        latest_outcomes.update(outcomes)
        state = state.with_outcomes(outcomes)
        delay = state.delay
        if delay:
            await sleeping.sleep_or_wait(
                min(delay, WAITING_KEEPALIVE_INTERVAL), asyncio.Event())

    # Activities assume that all handlers must eventually succeed.
    # We raise from the 1st exception only: just to have something real in the tracebacks.
    # For multiple handlers' errors, the logs should be investigated instead.
    exceptions = [
        outcome.exception for outcome in latest_outcomes.values()
        if outcome.exception is not None
    ]
    if exceptions:
        raise ActivityError("One or more handlers failed.", outcomes=latest_outcomes) \
            from exceptions[0]

    # If nothing has failed, we return identifiable results. The outcomes/states are internal.
    # The order of results is not guaranteed (the handlers can succeed on one of the retries).
    results = {
        handler_id: outcome.result
        for handler_id, outcome in latest_outcomes.items()
        if outcome.result is not None
    }
    return results
Пример #3
0
async def run_activity(
    *,
    lifecycle: lifecycles.LifeCycleFn,
    registry: registries.OperatorRegistry,
    activity: causation.Activity,
) -> Mapping[handlers.HandlerId, callbacks.HandlerResult]:
    logger = logging.getLogger(f'kopf.activities.{activity.value}')

    # For the activity handlers, we have neither bodies, nor patches, just the state.
    cause = causation.ActivityCause(logger=logger, activity=activity)
    handlers = registry.get_activity_handlers(activity=activity)
    outcomes = await handling.run_handlers_until_done(
        cause=cause,
        handlers=handlers,
        lifecycle=lifecycle,
    )

    # Activities assume that all handlers must eventually succeed.
    # We raise from the 1st exception only: just to have something real in the tracebacks.
    # For multiple handlers' errors, the logs should be investigated instead.
    exceptions = [
        outcome.exception for outcome in outcomes.values()
        if outcome.exception is not None
    ]
    if exceptions:
        raise ActivityError("One or more handlers failed.",
                            outcomes=outcomes) from exceptions[0]

    # If nothing has failed, we return identifiable results. The outcomes/states are internal.
    # The order of results is not guaranteed (the handlers can succeed on one of the retries).
    results = {
        handler_id: outcome.result
        for handler_id, outcome in outcomes.items()
        if outcome.result is not None
    }
    return results