Esempio n. 1
0
File: on.py Progetto: zhutony/kopf
 def decorator(
         fn: callbacks.ResourceHandlerFn) -> callbacks.ResourceHandlerFn:
     parent_handler = handling.handler_var.get()
     real_registry = registry if registry is not None else handling.subregistry_var.get(
     )
     real_id = registries.generate_id(
         fn=fn, id=id, prefix=parent_handler.id if parent_handler else None)
     handler = handlers.ResourceHandler(
         fn=fn,
         id=real_id,
         field=None,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         labels=labels,
         annotations=annotations,
         when=when,
         initial=None,
         deleted=None,
         requires_finalizer=None,
         reason=None,
     )
     real_registry.append(handler)
     return fn
Esempio n. 2
0
File: on.py Progetto: zhutony/kopf
 def decorator(
         fn: callbacks.ResourceHandlerFn) -> callbacks.ResourceHandlerFn:
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_resource = resources.Resource(group, version, plural)
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ResourceHandler(
         fn=fn,
         id=real_id,
         field=None,
         errors=None,
         timeout=None,
         retries=None,
         backoff=None,
         cooldown=None,
         labels=labels,
         annotations=annotations,
         when=when,
         initial=None,
         deleted=None,
         requires_finalizer=None,
         reason=None,
     )
     real_registry.resource_watching_handlers[real_resource].append(handler)
     return fn
Esempio n. 3
0
File: on.py Progetto: zer0n1/kopf
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     _warn_conflicting_values(field, value)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_field = dicts.parse_field(
         field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn, id=id)
     selector = references.Selector(group, version, plural)
     handler = handlers.ResourceChangingHandler(
         fn=fn,
         id=real_id,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         selector=selector,
         labels=labels,
         annotations=annotations,
         when=when,
         field=real_field,
         value=value,
         old=None,
         new=None,
         field_needs_change=False,
         initial=None,
         deleted=None,
         requires_finalizer=bool(not optional),
         reason=handlers.Reason.DELETE,
     )
     real_registry.resource_changing_handlers.append(handler)
     return fn
Esempio n. 4
0
 def decorator(fn: callbacks.ResourceTimerFn) -> callbacks.ResourceTimerFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_resource = resources.Resource(group, version, plural)
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ResourceTimerHandler(
         fn=fn,
         id=real_id,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         labels=labels,
         annotations=annotations,
         when=when,
         initial_delay=initial_delay,
         requires_finalizer=None,
         sharp=sharp,
         idle=idle,
         interval=interval,
     )
     real_registry.resource_spawning_handlers[real_resource].append(handler)
     return fn
Esempio n. 5
0
File: on.py Progetto: zer0n1/kopf
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ResourceWatchingFn, ) -> callbacks.ResourceWatchingFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     _warn_conflicting_values(field, value)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_field = dicts.parse_field(
         field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn, id=id)
     selector = references.Selector(group, version, plural)
     handler = handlers.ResourceWatchingHandler(
         fn=fn,
         id=real_id,
         errors=None,
         timeout=None,
         retries=None,
         backoff=None,
         cooldown=None,
         selector=selector,
         labels=labels,
         annotations=annotations,
         when=when,
         field=real_field,
         value=value,
     )
     real_registry.resource_watching_handlers.append(handler)
     return fn
Esempio n. 6
0
 def decorator(
         fn: callbacks.ResourceDaemonFn) -> callbacks.ResourceDaemonFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_resource = resources.Resource(group, version, plural)
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ResourceDaemonHandler(
         fn=fn,
         id=real_id,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         labels=labels,
         annotations=annotations,
         when=when,
         initial_delay=initial_delay,
         requires_finalizer=True,  #TODO: requires_finalizer? "optional"?
         cancellation_backoff=cancellation_backoff,
         cancellation_timeout=cancellation_timeout,
         cancellation_polling=cancellation_polling,
     )
     real_registry.resource_spawning_handlers[real_resource].append(handler)
     return fn
Esempio n. 7
0
 def decorator(
         fn: callbacks.ResourceChangingFn) -> callbacks.ResourceChangingFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_resource = resources.Resource(group, version, plural)
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ResourceChangingHandler(
         fn=fn,
         id=real_id,
         field=None,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         labels=labels,
         annotations=annotations,
         when=when,
         initial=None,
         deleted=None,
         requires_finalizer=bool(not optional),
         reason=handlers.Reason.DELETE,
     )
     real_registry.resource_changing_handlers[real_resource].append(handler)
     return fn
Esempio n. 8
0
File: on.py Progetto: zer0n1/kopf
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ResourceTimerFn, ) -> callbacks.ResourceTimerFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     _warn_conflicting_values(field, value)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_field = dicts.parse_field(
         field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn, id=id)
     selector = references.Selector(group, version, plural)
     handler = handlers.ResourceTimerHandler(
         fn=fn,
         id=real_id,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         selector=selector,
         labels=labels,
         annotations=annotations,
         when=when,
         field=real_field,
         value=value,
         initial_delay=initial_delay,
         requires_finalizer=True,
         sharp=sharp,
         idle=idle,
         interval=interval,
     )
     real_registry.resource_spawning_handlers.append(handler)
     return fn
Esempio n. 9
0
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     parent_handler = handling.handler_var.get()
     real_registry = registry if registry is not None else handling.subregistry_var.get(
     )
     real_id = registries.generate_id(
         fn=fn, id=id, prefix=parent_handler.id if parent_handler else None)
     handler = handlers.ResourceChangingHandler(
         fn=fn,
         id=real_id,
         field=None,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         labels=labels,
         annotations=annotations,
         when=when,
         initial=None,
         deleted=None,
         requires_finalizer=None,
         reason=None,
     )
     real_registry.append(handler)
     return fn
Esempio n. 10
0
File: on.py Progetto: zhutony/kopf
 def decorator(
         fn: callbacks.ResourceHandlerFn) -> callbacks.ResourceHandlerFn:
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_resource = resources.Resource(group, version, plural)
     real_field = dicts.parse_field(
         field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn,
                                      id=id,
                                      suffix=".".join(real_field or []))
     handler = handlers.ResourceHandler(
         fn=fn,
         id=real_id,
         field=real_field,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         labels=labels,
         annotations=annotations,
         when=when,
         initial=None,
         deleted=None,
         requires_finalizer=None,
         reason=None,
     )
     real_registry.resource_changing_handlers[real_resource].append(handler)
     return fn
Esempio n. 11
0
 def decorator(  # lgtm[py/similar-function]
         fn: callbacks.ResourceDaemonFn,
 ) -> callbacks.ResourceDaemonFn:
     _warn_conflicting_values(field, value)
     _verify_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry()
     real_field = dicts.parse_field(field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn, id=id, suffix=".".join(real_field or []))
     selector = references.Selector(
         __group_or_groupversion_or_name, __version_or_name, __name,
         group=group, version=version,
         kind=kind, plural=plural, singular=singular, shortcut=shortcut, category=category,
     )
     handler = handlers.ResourceDaemonHandler(
         fn=fn, id=real_id, param=param,
         errors=errors, timeout=timeout, retries=retries, backoff=backoff,
         selector=selector, labels=labels, annotations=annotations, when=when,
         field=real_field, value=value,
         initial_delay=initial_delay, requires_finalizer=True,
         cancellation_backoff=cancellation_backoff,
         cancellation_timeout=cancellation_timeout,
         cancellation_polling=cancellation_polling,
     )
     real_registry._resource_spawning.append(handler)
     return fn
Esempio n. 12
0
    def register(
        self,
        fn: AnyHandlerFn,
        *,
        id: Optional[str] = None,
        reason: Optional[handlers.Reason] = None,
        event: Optional[str] = None,  # deprecated, use `reason`
        field: Optional[dicts.FieldSpec] = None,
        errors: Optional[handlers.ErrorsMode] = None,
        timeout: Optional[float] = None,
        retries: Optional[int] = None,
        backoff: Optional[float] = None,
        cooldown: Optional[float] = None,  # deprecated, use `backoff`
        initial: Optional[bool] = None,
        deleted: Optional[bool] = None,
        requires_finalizer: bool = False,
        labels: Optional[filters.MetaFilter] = None,
        annotations: Optional[filters.MetaFilter] = None,
        when: Optional[callbacks.WhenFilterFn] = None,
    ) -> AnyHandlerFn:
        warnings.warn(
            "registry.register() is deprecated; "
            "use @kopf.on... decorators with registry= kwarg.",
            DeprecationWarning)

        if reason is None and event is not None:
            reason = handlers.Reason(event)

        real_field = dicts.parse_field(
            field) or None  # to not store tuple() as a no-field case.
        real_id = registries.generate_id(fn=fn,
                                         id=id,
                                         suffix=".".join(real_field or []))
        handler = LegacyAllPurposeResourcerHandler(
            id=real_id,
            fn=fn,  # type: ignore
            reason=reason,
            errors=errors,
            timeout=timeout,
            retries=retries,
            backoff=backoff,
            cooldown=cooldown,
            initial=initial,
            deleted=deleted,
            requires_finalizer=requires_finalizer,
            selector=None,
            labels=labels,
            annotations=annotations,
            when=when,
            field=real_field,
            value=None,
            old=None,
            new=None,
            field_needs_change=None,
        )
        self.append(handler)
        return fn
Esempio n. 13
0
 def decorator(  # lgtm[py/similar-function]
         fn: callbacks.ActivityFn,
 ) -> callbacks.ActivityFn:
     real_registry = registry if registry is not None else registries.get_default_registry()
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ActivityHandler(
         fn=fn, id=real_id, param=param,
         errors=errors, timeout=timeout, retries=retries, backoff=backoff,
         activity=handlers.Activity.AUTHENTICATION,
     )
     real_registry._activities.append(handler)
     return fn
Esempio n. 14
0
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn:
     _warn_conflicting_values(field, value)
     _verify_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_field = dicts.parse_field(
         field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn,
                                      id=id,
                                      suffix=".".join(real_field or []))
     selector = references.Selector(
         __group_or_groupversion_or_name,
         __version_or_name,
         __name,
         group=group,
         version=version,
         kind=kind,
         plural=plural,
         singular=singular,
         shortcut=shortcut,
         category=category,
     )
     handler = handlers.ResourceChangingHandler(
         fn=fn,
         id=real_id,
         param=param,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         selector=selector,
         labels=labels,
         annotations=annotations,
         when=when,
         field=real_field,
         value=value,
         old=None,
         new=None,
         field_needs_change=False,
         initial=None,
         deleted=None,
         requires_finalizer=bool(not optional),
         reason=handlers.Reason.DELETE,
     )
     real_registry._resource_changing.append(handler)
     return fn
Esempio n. 15
0
 def decorator(fn: callbacks.ActivityFn) -> callbacks.ActivityFn:
     _warn_deprecated_signatures(fn)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ActivityHandler(
         fn=fn,
         id=real_id,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         activity=handlers.Activity.STARTUP,
     )
     real_registry.activity_handlers.append(handler)
     return fn
Esempio n. 16
0
File: on.py Progetto: zhutony/kopf
 def decorator(
         fn: callbacks.ActivityHandlerFn) -> callbacks.ActivityHandlerFn:
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ActivityHandler(
         fn=fn,
         id=real_id,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         activity=causation.Activity.CLEANUP,
     )
     real_registry.activity_handlers.append(handler)
     return fn
Esempio n. 17
0
File: on.py Progetto: zer0n1/kopf
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn:
     parent_handler = handling.handler_var.get()
     if not isinstance(parent_handler, handlers.ResourceChangingHandler):
         raise TypeError(
             "Sub-handlers are only supported for resource-changing handlers."
         )
     _warn_incompatible_parent_with_oldnew(parent_handler, old, new)
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     _warn_conflicting_values(field, value, old, new)
     real_registry = registry if registry is not None else handling.subregistry_var.get(
     )
     real_field = dicts.parse_field(
         field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(
         fn=fn, id=id, prefix=parent_handler.id if parent_handler else None)
     handler = handlers.ResourceChangingHandler(
         fn=fn,
         id=real_id,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         cooldown=cooldown,
         selector=None,
         labels=labels,
         annotations=annotations,
         when=when,
         field=real_field,
         value=value,
         old=old,
         new=new,
         field_needs_change=parent_handler.
         field_needs_change,  # inherit dymaically
         initial=None,
         deleted=None,
         requires_finalizer=None,
         reason=None,
     )
     real_registry.append(handler)
     return fn
Esempio n. 18
0
 def decorator(  # lgtm[py/similar-function]
         fn: callbacks.ResourceWatchingFn,
 ) -> callbacks.ResourceWatchingFn:
     _warn_conflicting_values(field, value)
     _verify_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry()
     real_field = dicts.parse_field(field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn, id=id)
     selector = references.Selector(
         __group_or_groupversion_or_name, __version_or_name, __name,
         group=group, version=version,
         kind=kind, plural=plural, singular=singular, shortcut=shortcut, category=category,
     )
     handler = handlers.ResourceWatchingHandler(
         fn=fn, id=real_id,
         errors=None, timeout=None, retries=None, backoff=None,
         selector=selector, labels=labels, annotations=annotations, when=when,
         field=real_field, value=value,
     )
     real_registry._resource_watching.append(handler)
     return fn
Esempio n. 19
0
 def decorator(
         fn: callbacks.ResourceWatchingFn) -> callbacks.ResourceWatchingFn:
     _warn_deprecated_signatures(fn)
     _warn_deprecated_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry(
     )
     real_resource = resources.Resource(group, version, plural)
     real_id = registries.generate_id(fn=fn, id=id)
     handler = handlers.ResourceWatchingHandler(
         fn=fn,
         id=real_id,
         errors=None,
         timeout=None,
         retries=None,
         backoff=None,
         cooldown=None,
         labels=labels,
         annotations=annotations,
         when=when,
     )
     real_registry.resource_watching_handlers[real_resource].append(handler)
     return fn
Esempio n. 20
0
 def decorator(  # lgtm[py/similar-function]
         fn: callbacks.ResourceWebhookFn,
 ) -> callbacks.ResourceWebhookFn:
     _warn_conflicting_values(field, value)
     _verify_filters(labels, annotations)
     real_registry = registry if registry is not None else registries.get_default_registry()
     real_field = dicts.parse_field(field) or None  # to not store tuple() as a no-field case.
     real_id = registries.generate_id(fn=fn, id=id, suffix=".".join(real_field or []))
     selector = references.Selector(
         __group_or_groupversion_or_name, __version_or_name, __name,
         group=group, version=version,
         kind=kind, plural=plural, singular=singular, shortcut=shortcut, category=category,
     )
     handler = handlers.ResourceWebhookHandler(
         fn=fn, id=real_id, param=param,
         errors=None, timeout=None, retries=None, backoff=None,  # TODO: add some meaning later
         selector=selector, labels=labels, annotations=annotations, when=when,
         field=real_field, value=value,
         reason=handlers.WebhookType.MUTATING, operation=operation,
         persistent=persistent, side_effects=side_effects, ignore_failures=ignore_failures,
     )
     real_registry._resource_webhooks.append(handler)
     return fn
Esempio n. 21
0
async def execute(
    *,
    fns: Optional[Iterable[callbacks.ResourceChangingFn]] = None,
    handlers: Optional[Iterable[handlers_.ResourceChangingHandler]] = None,
    registry: Optional[registries.ResourceChangingRegistry] = None,
    lifecycle: Optional[lifecycles.LifeCycleFn] = None,
    cause: Optional[causation.BaseCause] = None,
) -> None:
    """
    Execute the handlers in an isolated lifecycle.

    This function is just a public wrapper for `execute` with multiple
    ways to specify the handlers: either as the raw functions, or as the
    pre-created handlers, or as a registry (as used in the object handling).

    If no explicit functions or handlers or registry are passed,
    the sub-handlers of the current handler are assumed, as accumulated
    in the per-handler registry with ``@kopf.subhandler``.

    If the call to this method for the sub-handlers is not done explicitly
    in the handler, it is done implicitly after the handler is exited.
    One way or another, it is executed for the sub-handlers.
    """

    # Restore the current context as set in the handler execution cycle.
    lifecycle = lifecycle if lifecycle is not None else sublifecycle_var.get()
    lifecycle = lifecycle if lifecycle is not None else lifecycles.get_default_lifecycle(
    )
    cause = cause if cause is not None else cause_var.get()
    parent_handler: handlers_.BaseHandler = handler_var.get()
    parent_prefix = parent_handler.id if parent_handler is not None else None

    # Validate the inputs; the function signatures cannot put these kind of restrictions, so we do.
    if len([v for v in [fns, handlers, registry] if v is not None]) > 1:
        raise TypeError(
            "Only one of the fns, handlers, registry can be passed. Got more.")

    elif fns is not None and isinstance(fns, collections.abc.Mapping):
        subregistry = registries.ResourceChangingRegistry()
        for id, fn in fns.items():
            real_id = registries.generate_id(fn=fn,
                                             id=id,
                                             prefix=parent_prefix)
            handler = handlers_.ResourceChangingHandler(
                fn=fn,
                id=real_id,
                errors=None,
                timeout=None,
                retries=None,
                backoff=None,
                cooldown=None,
                selector=None,
                labels=None,
                annotations=None,
                when=None,
                initial=None,
                deleted=None,
                requires_finalizer=None,
                reason=None,
                field=None,
                value=None,
                old=None,
                new=None,
                field_needs_change=None,
            )
            subregistry.append(handler)

    elif fns is not None and isinstance(fns, collections.abc.Iterable):
        subregistry = registries.ResourceChangingRegistry()
        for fn in fns:
            real_id = registries.generate_id(fn=fn,
                                             id=None,
                                             prefix=parent_prefix)
            handler = handlers_.ResourceChangingHandler(
                fn=fn,
                id=real_id,
                errors=None,
                timeout=None,
                retries=None,
                backoff=None,
                cooldown=None,
                selector=None,
                labels=None,
                annotations=None,
                when=None,
                initial=None,
                deleted=None,
                requires_finalizer=None,
                reason=None,
                field=None,
                value=None,
                old=None,
                new=None,
                field_needs_change=None,
            )
            subregistry.append(handler)

    elif fns is not None:
        raise ValueError(
            f"fns must be a mapping or an iterable, got {fns.__class__}.")

    elif handlers is not None:
        subregistry = registries.ResourceChangingRegistry()
        for handler in handlers:
            subregistry.append(handler)

    # Use the registry as is; assume that the caller knows what they do.
    elif registry is not None:
        subregistry = registry

    # Prevent double implicit execution.
    elif subexecuted_var.get():
        return

    # If no explicit args were passed, use the accumulated handlers from `@kopf.subhandler`.
    else:
        subexecuted_var.set(True)
        subregistry = subregistry_var.get()

    # The sub-handlers are only for upper-level causes, not for lower-level events.
    if not isinstance(cause, causation.ResourceChangingCause):
        raise RuntimeError(
            "Sub-handlers of event-handlers are not supported and have "
            "no practical use (there are no retries or state tracking).")

    # Execute the real handlers (all or few or one of them, as per the lifecycle).
    settings: configuration.OperatorSettings = subsettings_var.get()
    owned_handlers = subregistry.get_resource_handlers(resource=cause.resource)
    cause_handlers = subregistry.get_handlers(cause=cause)
    storage = settings.persistence.progress_storage
    state = states.State.from_storage(body=cause.body,
                                      storage=storage,
                                      handlers=owned_handlers)
    state = state.with_purpose(cause.reason).with_handlers(cause_handlers)
    outcomes = await execute_handlers_once(
        lifecycle=lifecycle,
        settings=settings,
        handlers=cause_handlers,
        cause=cause,
        state=state,
    )
    state = state.with_outcomes(outcomes)
    state.store(body=cause.body, patch=cause.patch, storage=storage)
    states.deliver_results(outcomes=outcomes, patch=cause.patch)

    # Enrich all parents with references to sub-handlers of any level deep (sub-sub-handlers, etc).
    # There is at least one container, as this function can be called only from a handler.
    subrefs_containers: Iterable[Set[handlers_.HandlerId]] = subrefs_var.get()
    for key in state:
        for subrefs_container in subrefs_containers:
            subrefs_container.add(key)

    # Escalate `HandlerChildrenRetry` if the execute should be continued on the next iteration.
    if not state.done:
        raise HandlerChildrenRetry(delay=state.delay)