async def custom_object_handler( lifecycle: Callable, registry: registries.GlobalRegistry, resource: registries.Resource, event: dict, freeze: asyncio.Event, ) -> None: """ Handle a single custom object low-level watch-event. Convert the low-level events, as provided by the watching/queueing tasks, to the high-level causes, and then call the cause-handling logic. All the internally provoked changes are intercepted, do not create causes, and therefore do not call the handling logic. """ body = event['object'] delay = None patch = {} # Each object has its own prefixed logger, to distinguish parallel handling. logger = ObjectLogger( logging.getLogger(__name__), extra=dict( namespace=body.get('metadata', {}).get('namespace', 'default'), name=body.get('metadata', {}).get('name', body.get('metadata', {}).get('uid', None)), )) # If the global freeze is set for the processing (i.e. other operator overrides), do nothing. if freeze.is_set(): logger.debug("Ignoring the events due to freeze.") return # Invoke all silent spies. No causation, no progress storage is performed. if registry.has_event_handlers(resource=resource): await handle_event(registry=registry, resource=resource, event=event, logger=logger, patch=patch) # Object patch accumulator. Populated by the methods. Applied in the end of the handler. # Detect the cause and handle it (or at least log this happened). if registry.has_cause_handlers(resource=resource): cause = causation.detect_cause(event=event, resource=resource, logger=logger, patch=patch) delay = await handle_cause(lifecycle=lifecycle, registry=registry, cause=cause) # Provoke a dummy change to trigger the reactor after sleep. # TODO: reimplement via the handler delayed statuses properly. if delay and not patch: patch.setdefault('status', {}).setdefault( 'kopf', {})['dummy'] = datetime.datetime.utcnow().isoformat() # Whatever was done, apply the accumulated changes to the object. # But only once, to reduce the number of API calls and the generated irrelevant events. if patch: logger.debug("Patching with: %r", patch) await patching.patch_obj(resource=resource, patch=patch, body=body) # Sleep strictly after patching, never before -- to keep the status proper. if delay: logger.info(f"Sleeping for {delay} seconds for the delayed handlers.") await asyncio.sleep(delay)
async def custom_object_handler( lifecycle: Callable, registry: registries.GlobalRegistry, resource: registries.Resource, event: dict, freeze: asyncio.Event, replenished: asyncio.Event, event_queue: asyncio.Queue, ) -> None: """ Handle a single custom object low-level watch-event. Convert the low-level events, as provided by the watching/queueing tasks, to the high-level causes, and then call the cause-handling logic. All the internally provoked changes are intercepted, do not create causes, and therefore do not call the handling logic. """ body = event['object'] delay = None patch = {} # Each object has its own prefixed logger, to distinguish parallel handling. logger = logging_engine.ObjectLogger(body=body) posting.event_queue_loop_var.set(asyncio.get_running_loop()) posting.event_queue_var.set( event_queue) # till the end of this object's task. # If the global freeze is set for the processing (i.e. other operator overrides), do nothing. if freeze.is_set(): logger.debug("Ignoring the events due to freeze.") return # Invoke all silent spies. No causation, no progress storage is performed. if registry.has_event_handlers(resource=resource): await handle_event(registry=registry, resource=resource, event=event, logger=logger, patch=patch) # Object patch accumulator. Populated by the methods. Applied in the end of the handler. # Detect the cause and handle it (or at least log this happened). if registry.has_cause_handlers(resource=resource): extra_fields = registry.get_extra_fields(resource=resource) old, new, diff = lastseen.get_state_diffs(body=body, extra_fields=extra_fields) cause = causation.detect_cause( event=event, resource=resource, logger=logger, patch=patch, old=old, new=new, diff=diff, requires_finalizer=registry.requires_finalizer(resource=resource), ) delay = await handle_cause(lifecycle=lifecycle, registry=registry, cause=cause) # Whatever was done, apply the accumulated changes to the object. # But only once, to reduce the number of API calls and the generated irrelevant events. if patch: logger.debug("Patching with: %r", patch) await patching.patch_obj(resource=resource, patch=patch, body=body) # Sleep strictly after patching, never before -- to keep the status proper. # The patching above, if done, interrupts the sleep instantly, so we skip it at all. if delay and not patch: logger.debug(f"Sleeping for {delay} seconds for the delayed handlers.") unslept = await sleeping.sleep_or_wait(delay, replenished) if unslept is not None: logger.debug( f"Sleeping was interrupted by new changes, {unslept} seconds left." ) else: dummy = { 'status': { 'kopf': { 'dummy': datetime.datetime.utcnow().isoformat() } } } logger.debug("Provoking reaction with: %r", dummy) await patching.patch_obj(resource=resource, patch=dummy, body=body)