The core worker loop for the module, responsible for handling events from the incoming event queue. This method is a coroutine and is run asynchronously. Multiple instances can run simultaneously based on the 'module_threads' configuration. The worker dequeues events from '
(self)
| 715 | return self, status, str(msg) |
| 716 | |
| 717 | async def _worker(self): |
| 718 | """ |
| 719 | The core worker loop for the module, responsible for handling events from the incoming event queue. |
| 720 | |
| 721 | This method is a coroutine and is run asynchronously. Multiple instances can run simultaneously based on |
| 722 | the 'module_threads' configuration. The worker dequeues events from 'incoming_event_queue', performs |
| 723 | necessary prechecks, and passes the event to the appropriate handler function. |
| 724 | |
| 725 | Args: |
| 726 | None |
| 727 | |
| 728 | Returns: |
| 729 | None |
| 730 | |
| 731 | Raises: |
| 732 | asyncio.CancelledError: If the worker is cancelled during its operation. |
| 733 | |
| 734 | Notes: |
| 735 | - The worker is sensitive to the 'stopping' flag of the scan. It will terminate if this flag is set. |
| 736 | - The worker handles backpressure by pausing when the outgoing event queue is full. |
| 737 | - Batch processing is supported and is activated when 'batch_size' > 1. |
| 738 | - Each event is subject to a post-check via '_event_postcheck()' to decide whether it should be handled. |
| 739 | - Special 'FINISHED' events trigger the 'finish()' method of the module. |
| 740 | """ |
| 741 | async with self.scan._acatch(context=self._worker, unhandled_is_critical=True): |
| 742 | try: |
| 743 | while not self.scan.stopping and not self.errored: |
| 744 | # if batch wasn't big enough, we wait for the next event before continuing |
| 745 | if self.batch_size > 1: |
| 746 | submitted = await self._handle_batch() |
| 747 | if not submitted: |
| 748 | async with self.event_received: |
| 749 | await self.event_received.wait() |
| 750 | |
| 751 | else: |
| 752 | try: |
| 753 | if self.incoming_event_queue is not False: |
| 754 | event = await self.incoming_event_queue.get() |
| 755 | else: |
| 756 | self.debug("Event queue is in bad state") |
| 757 | break |
| 758 | except asyncio.queues.QueueEmpty: |
| 759 | continue |
| 760 | self.debug(f"Got {event} from {getattr(event, 'module', 'unknown_module')}") |
| 761 | async with self._task_counter.count(f"event_postcheck({event})"): |
| 762 | acceptable, reason = await self._event_postcheck(event) |
| 763 | if acceptable: |
| 764 | if event.type == "FINISHED": |
| 765 | context = f"{self.name}.finish()" |
| 766 | try: |
| 767 | await self.run_task(self.finish(), context) |
| 768 | except asyncio.CancelledError: |
| 769 | self.debug(f"{context} was cancelled") |
| 770 | continue |
| 771 | else: |
| 772 | context = f"{self.name}.handle_event({event})" |
| 773 | self.scan.stats.event_consumed(event, self) |
| 774 | self.debug(f"Handling {event}") |
no test coverage detected