hurah/events

Event handling / task delegation system based on inotifywait

v1.0.26 2024-06-12 16:59 UTC

This package is auto-updated.

Last update: 2024-07-12 17:07:16 UTC


README

A simple file based task delegation solution.

⚠️ No locking: This package is intended as a simple solution for task delegation in situations where scaling won't be an issue. It assumes each handler for a specific task runs only once. Running multiple instances of the same handler concurrently may result in tasks being executed multiple times.

Use cases

  • Make generic software extensible.
  • Move time consuming work to a separate background process.
  • Prevent slow or possibly unavailable resources from slowing down the performance of your system.

Installation

    composer require hurah/events

Setup

Since this is a file based system, an empty directory is needed for the system to store it's data in. Running the handler can probably best be done with something like Inotifywait if you want to have the event handler to run as close to real-time as possible. A cron job could also be used if some delay is not an issue and Inotifywait cannot be installed.

Dispatch an event

From the code where a task or some tasks need to be delegated

$exampleContextData = ['product_id' => 123];
$dispatcher = new Dispatcher('/some/root/directory/where/events/will/live');
$dispatcher->dispatch('product/created', $exampleContextData);

Implement handler(s)

Create a new class and have it extend AbstractHandler. In it's most basic form your handler will only implement handleTask which you should use to implement the logic required to do whatever job you have in mind.

class MyHandler extends AbstractHandler
{
    protected function handleTask(Context $myTaskData): int
    {
      return Task::SUCCESS;
    }
}

Return type and failures

When implementing your handler as above, you must return the right directive for the handler to know what to do next.

Events

When an event is dispatched, it’s identified by a unique name (e.g. product/created), which any number of handlers might be listening to. A sepearate json file containing the context data is stored for each handler. When the handler is triggered each job is executed in sequential order.

Event tree

The event type is made up out of one or more strings separated by a forward slash. Event listeners can be bound to any level of the event tree. A listener that is set up to listen for "product" events will be triggered when a "product/created" event was dispatched etc.

Running handlers

You need some mechanism to trigger the handler code on demand or (not favorable) run the handler code periodically to check for new events and handle them.

Manual / periodically

php bin/application.php worker:runner <handler_name> <event_type> <handler> <event_root>

On demand / automatically

The bin folder contains the bash script below which you can use to monitor event directories. This script should run an a per event basis, probably using supervisor or perhaps systemd to autorestart in case something fails.

#!/bin/sh

# Usage:
# ./inotify-wait.sh <event-directory> <handler-name> <handler-fully-qualified-class-name>
#


echo "Starting listener in $1"
DIRECTORY="$1/$3/$2_listener/inbox"

echo "Event directory $DIRECTORY";

if [ ! -d "$DIRECTORY" ]; then
  echo "Creating $DIRECTORY which will act as the event inbox"
  mkdir -p "$DIRECTORY"
fi

inotifywait -m "$DIRECTORY" -e create |
    while read path action file; do
	       echo "$action - $path - $file"
	       /usr/bin/pwd
        /usr/bin/php ./application.php worker:runner $2 $3 $4 $1
    done

echo "Listener stopped"

antonboutkam