kylevorster's avatar

Event Performance Question

I've got a fairly massive system running a lot of one action objects to keep my controllers cleaner. There's some logic in my action classes that could be refactored into events.

Question is, how much load would events cause if I use them all over the show, example below, I'm using RabbitMQ as a queue service, so events will already be queued.

Ignore naming of stuff, I just wrote the code without running etc.

<?php

namespace App\Actions;

abstract class ActionBase
{

    protected function getEventName(): string
    {
        return snake_case(class_basename($this));
    }

    protected function firePreEvent(... $data): void
    {
        event("actions.{$this->getEventName()}.pre", $data);
    }

    public function firePostEvent(): void
    {
        event("actions.{$this->getEventName()}.post", $data);
    }

    public function fireErrorEvent(): void
    {
        event("actions.{$this->getEventName()}.error", $data);
    }

}

final class CreateUser extends ActionBase
{
    public function execute(array $data)
    {
        $this->firePreEvent($data);

        // doing something

        if($error == true)
        {
            $this->fireErrorEvent($data);

            return false;
        }

        $processed_data = ['foo' => 'bar'];

        $this->firePostEvent($processed_data);
    }
}

Event Service Provider

protected $listen = [
    'actions.*.pre' => [
        'App\Listeners\Auditing\PreActionAudit',
    ],
    'actions.*.post' => [
        'App\Listeners\Auditing\PostActionAudit',
    ],
    'actions.*.error' => [
        'App\Listeners\Auditing\ErrorActionAudit',
    ],
    'actions.create_user.post' => [
        'App\Listeners\Notifications\EmailUser'
    ],
    'actions.create_user.error' => [
        'App\Listeners\Notifications\EmailOnFailure',
        'App\Notifications\SlackNotice',
        'App\Listeners\LogIt',
    ],
]
0 likes
2 replies
Snapey's avatar

The performance hit is queuing and dequeuing data (serialize/deserialize) effectively handling the data three times instead of once. The performance gain is the ability to use otherwise idle time to perform work and the ability to scale horizontally by having workers on other servers.

So its a balance and compromise, and any time you have this, there is no right answer.

Obviously the more you make async, the more you have to put in checks and error handling for race conditions. Eg, now you have to handle the scenario where the user wants to update their profile but you have not yet created it.

kylevorster's avatar

@snapey thanks for your reply, think I should have added a bit more detail. It's just a example, don't judge why I'm doing Arr::get, there's many better ways.

final class CreateUser extends ActionBase
{
    public function execute(array $data)
    {
        $this->firePreEvent($data);

        $user_data = [
            'name' => Arr::get($data, 'firstname') . ' ' .  Arr::get($data, 'lastname'),
            'email' => Arr::get($data, 'mail_address')
        ];
        
        try {
            
            $user = User::create($user_data);
            
        } catch(\ModelException $exception)
        {
            $this->fireErrorEvent($data, $user_data, $exception->getMessage());
            
            throw new UserCreationException('Unable to create the user, please try again later.');
        }
        
        $this->firePostEvent($user);
        
        return true;
    }
}

So user will be created and basic error handling to ensure the main part of the code is done, now the events can handle inserting a user count, doing audit etc.

Please or to participate in this conversation.