My first hunch is that auth()->user() is null once the queued job is handled asynchronously.
Perhaps you could run this locally with dd(auth()->user()) to verify my hunch. However, I'd also imagine you'd be getting a cannot call method 'notify' on null style exception if you run this currently and my hunch is accurate. Does this land in your failed jobs list with an exception if you run it?
Tip: if you do test locally, remember to set your local environment's QUEUE_CONNECTION to something other than sync or null. Otherwise, you'll get unhelpful results, as the action will be handled synchronously (during the request) when auth()->user() is non-null (or in the case of a null queue connection, the job won't be handled at all).
Assuming I'm correct, here are some recommendations to solve the issue:
Since it's evident from your code that you're attempting to notify the admin using Nova that triggered the action, perhaps you could resolve the user from a database query instead of the auth()->user() helper. Something like:
User::getDefaultAdmin()->notify(new BackupJobUpdateFinished($model));
If you have multiple admins of your system, then you might be looking to resolve the specific admin that started the action. In that case, I'd recommend:
- In the action's
handlemethod, manuallydispatchaBackupJobfor the$models, where you can pass in a particular$userto the job's constructor to use for your notification. This also let's this "job handling" logic exist in one place and your Nova action simply leverages that existing code, staying DRY. Not to mention, this lets you utilize thefailed()method of Laravel's Job class to handle the notification so that you can get away from theif ... elselogic. https://laravel.com/docs/8.x/queues#cleaning-up-after-failed-jobs. Obviously, if you choose this path, your Nova action itself no longer needs to be queued. - Alternatively, you might be able to use the Nova action's
__construct()method to pass in the particular admin user and that should get serialized into the job. I honestly haven't tried this strategy before, because I prefer to leverage my existing Jobs in the system (the option above). Nonetheless, if this does work, then you could do something like:
// Nova action
public User $admin;
public function __construct(?User $admin = null)
{
$this->admin = $admin ?? auth()->user();
}
public function handle(ActionFields $fields, Collection $models)
{
foreach ($models as $model) {
$res = Artisan::call('backup-jobs:update ' . $model->host->fqdn);
if ($res >= 1) {
$this->markAsFinished($model);
$this->admin->notify(new BackupJobUpdateFinished($model));
} else {
$this->markAsFailed($model);
$this->admin->notify(new BackupJobUpdateFailed($model));
}
}
}
Hope this helps.