Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error in Queue ShouldBroadcast since 3.8.5 #1263

Open
jetwes opened this issue Oct 7, 2024 · 24 comments
Open

Error in Queue ShouldBroadcast since 3.8.5 #1263

jetwes opened this issue Oct 7, 2024 · 24 comments
Assignees
Labels
bug Something isn't working

Comments

@jetwes
Copy link

jetwes commented Oct 7, 2024

Bug description

I always get an error "Database connection [tenant] not configured." on an event that implements Shouldbroadcast.
This error was introduced since upgrading to 3.8.5 - downgrading to 3.8.4 resolves the issue.

Steps to reproduce

Create a event that implements ShouldBroadcast with broadcastOn and broadcastWith method.

Expected behavior

No error

Laravel version

10.48.22

stancl/tenancy version

3.8.5

@jetwes jetwes added the bug Something isn't working label Oct 7, 2024
@stancl
Copy link
Member

stancl commented Oct 7, 2024

Please post the code of the event.

@jetwes
Copy link
Author

jetwes commented Oct 7, 2024

This is ONE example - happens with other events, too:

@jetwes
Copy link
Author

jetwes commented Oct 7, 2024

`<?php

namespace App\Events\Tickets;

use App\Models\Tenant;
use App\Models\Ticket;
use App\Models\TicketComment;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class TicketCommentCreated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public Ticket $ticket;
public array $users = [];

/**
 * Create a new event instance.
 */
public function __construct(public TicketComment $ticketComment, public Tenant $tenant, public bool $notifyAgent = false)
{
    $this->ticket = Ticket::query()
        ->where('id', $this->ticketComment->ticket_id)
        ->with(['user', 'agent'])
        ->first();
    //get the user_ids for notification
    if ($this->notifyAgent) {
        //for system category
        if ($this->ticket->category_id === 1) {
            foreach(User::where('active', 1)
                        ->where(function (Builder $query) {
                            $query->where('email', 'y@x)
                                ->orWhere('email', 'y@x')
                                ->orWhere('email', 'y@x');
                        })->get() as $user) {
                $this->users[] = $user;
            }
        }
        else {
            $this->users[] = $this->ticket->agent;
        }
    }
    if ($this->ticketComment->user_id != $this->ticket->user_id)
        $this->users[] = $this->ticket->user;
}

/**
 * Get the channels the event should broadcast on.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(): array
{
    $notify = [];
    foreach ($this->users as $user)
        $notify[] = new PrivateChannel($this->tenant->id.'.tickets.'.$user->id);

    return $notify;
}

public function broadcastWith()
{
    $user = User::where('id', $this->ticketComment->user_id)->first();
    return [
        'title' => 'Neuer Ticket Kommentar',
        'message' => 'Neuer Kommentar im Ticket "'.$this->ticket->subject.'" von '.$user->full_name,
        'ticket_id' => $this->ticket->id
    ];
}

}
`

@stancl
Copy link
Member

stancl commented Oct 7, 2024

Double check that your queues are configured correctly per the documentation. If they are, create a minimal reproduction example that we can use. See #1260

@jetwes
Copy link
Author

jetwes commented Oct 7, 2024

We have a correct configured redis queue which worked perfectly well since 1,5 years...
I'll have to check wether i can give au minimal reproduction platform. It's a closed app.

@stancl
Copy link
Member

stancl commented Oct 7, 2024

A minimal reproduction is written from scratch, so it doesn't matter what business logic you have in your application.

@jetwes
Copy link
Author

jetwes commented Oct 7, 2024

I'm aware of that - but i want to show it as detailled as possible. And i'll have to look what timeframe i have. I'll look what i can do.

@stancl
Copy link
Member

stancl commented Oct 7, 2024

It should have as little detail (and therefore as few variables and moving parts) as possible, hence minimal reproduction. The least amount of code/simplest setup that reproduces this, so that I can track down where the issue is.

@iolk
Copy link

iolk commented Oct 9, 2024

Similar issue here and downgrading to 3.8.4 resolves the issue.
It looks like the subscribers are no longer in the tenant context.

We have a subscriber registered in the EventServiceProvider:

class JobEventSubscriber
{
    public function handleEvent(JobProcessed|JobFailed $event): void
    {
        Log::debug(tenant()?->id);
        // ^ this is null, in 3.8.4 this is not null 
        
        $jobBody = data_get(json_decode($event->job->getRawBody()), 'data.command');
        if ($jobBody == null) {
            return;
        }

        $job = unserialize($jobBody);
        // ^ this throws error "Database connection [tenant] not configured."
        // other stuff
    }

    public function subscribe(Dispatcher $events): array
    {
        return [
            JobProcessed::class => 'handleEvent',
            JobFailed::class => 'handleEvent',
        ];
    }
}

@stancl
Copy link
Member

stancl commented Oct 9, 2024

That's kind of a separate issue since you're hooking into the queue lifecycle directly. The reports were that the old behavior in 3.8.4 made queue:restart signals not get noticed by the worker if it remained in the tenant context after processing a job, so the only thing we could do here would be adding some static properties to hook into our own listeners.

@briggsm
Copy link

briggsm commented Oct 12, 2024

I'm 99% sure I'm seeing the same problem. I'll add details from my perspective that should help you in debugging.

I've only tested locally with Sail so far, but I'm pretty sure this would happen on a server too.

Works with 3.8.4, fails with 3.8.5.

I'm starting with the bare bones (out of the box) saas-boilerplate.

Get everything up and running:

sail up
sail npm install
sail npm run dev
sail artisan queue:listen
tail -n 100 -f storage/logs/laravel.log

Then in routes/tenant.php, I add the following Temp Route:

Route::middleware('tenant', PreventAccessFromCentralDomains::class)->name('tenant.')->group(function () {
	// Other routes...
	
	Route::middleware(['auth', CheckSubscription::class])->group(function () {
		// Other routes...
		
		// Temp Route to test notifications
		Route::get('/send-unread-message-notification/{post}', function (Post $post) {
		    $author = $post->author;

		    $postData = [
		        'id' => $post->id,
		        'title' => $post->title,
		        'body' => $post->body,
		    ];

		    if ($author) {
		        $author->notify(new UnreadMessageNotification($postData));  // Queue it - this works on 3.8.4, fails on 3.8.5
		        // Notification::sendNow($author, new UnreadMessageNotification($postData)); // This always works
		        return response()->json(['status' => 'Notification of Post sent successfully.']);
		    }

		    return response()->json(['status' => 'Author not found.'], 404);
		});
	});
});

app/Notifications/UnreadMessageNotification.php:

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;

class UnreadMessageNotification extends Notification implements ShouldQueue
{
    use Queueable;

    protected $postData;

    public function __construct(array $postData)
    {
        $this->postData = $postData;
    }

    public function via($notifiable)
    {
        return ['database'];
    }

    public function toArray($notifiable)
    {
        return [
            'post_id' => $this->postData['id'],
            'title' => $this->postData['title'],
            'body' => $this->postData['body'],
        ];
    }
}

Create a tenant (u1) via http://localhost/register (so final subdomain is u1.localhost)

Then in browser I go to:
http://u1.localhost/send-unread-message-notification/1

Running 3.8.4, I get:

2024-10-12 06:49:23 App\Notifications\UnreadMessageNotification .... RUNNING
2024-10-12 06:49:24 App\Notifications\UnreadMessageNotification  59.69ms DONE

(and no errors in laravel.log)

Running 3.8.5, I get:

2024-10-12 06:22:08 App\Notifications\UnreadMessageNotification .... RUNNING

And in laravel.log:

[2024-10-12 06:22:08] local.ERROR: Database connection [tenant] not configured. {"exception":"[object] (InvalidArgumentException(code: 0): Database connection [tenant] not configured. at /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php:188)
[stacktrace]
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php(151): Illuminate\\Database\\DatabaseManager->configuration()
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php(93): Illuminate\\Database\\DatabaseManager->makeConnection()
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1850): Illuminate\\Database\\DatabaseManager->connection()
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1816): Illuminate\\Database\\Eloquent\\Model::resolveConnection()
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(1574): Illuminate\\Database\\Eloquent\\Model->getConnection()
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(1492): Illuminate\\Database\\Eloquent\\Model->getDateFormat()
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(247): Illuminate\\Database\\Eloquent\\Model->asDateTime()
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(208): Illuminate\\Database\\Eloquent\\Model->addDateAttributesToArray()
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1664): Illuminate\\Database\\Eloquent\\Model->attributesToArray()
#9 [internal function]: Illuminate\\Database\\Eloquent\\Model->Illuminate\\Database\\Eloquent\\{closure}()
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/PreventsCircularRecursion.php(46): call_user_func()
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1663): Illuminate\\Database\\Eloquent\\Model->withoutRecursion()
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1695): Illuminate\\Database\\Eloquent\\Model->toArray()
#13 [internal function]: Illuminate\\Database\\Eloquent\\Model->jsonSerialize()
#14 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(146): json_encode()
#15 [internal function]: Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->Laravel\\Telescope\\Storage\\{closure}()
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Arr.php(605): array_map()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Collection.php(789): Illuminate\\Support\\Arr::map()
#18 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(145): Illuminate\\Support\\Collection->map()
#19 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(257): Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->Laravel\\Telescope\\Storage\\{closure}()
#20 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(144): Illuminate\\Support\\Collection->each()
#21 /var/www/html/vendor/laravel/telescope/src/Telescope.php(661): Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->store()
#22 [internal function]: Laravel\\Telescope\\Telescope::Laravel\\Telescope\\{closure}()
#23 /var/www/html/vendor/laravel/telescope/src/Telescope.php(286): call_user_func()
#24 /var/www/html/vendor/laravel/telescope/src/Telescope.php(653): Laravel\\Telescope\\Telescope::withoutRecording()
#25 /var/www/html/vendor/laravel/telescope/src/ListensForStorageOpportunities.php(65): Laravel\\Telescope\\Telescope::store()
#26 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Laravel\\Telescope\\Telescope::Laravel\\Telescope\\{closure}()
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#28 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(83): Illuminate\\Container\\Util::unwrapIfClosure()
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\Container\\BoundMethod::callBoundMethod()
#30 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(690): Illuminate\\Container\\BoundMethod::call()
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1420): Illuminate\\Container\\Container->call()
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(218): Illuminate\\Foundation\\Application->terminate()
#33 /var/www/html/artisan(51): Illuminate\\Foundation\\Console\\Kernel->terminate()
#34 {main}
"}

@stancl
Copy link
Member

stancl commented Oct 12, 2024

Thanks for the detailed info @briggsm. Could you please also test without Telescope (should be possible to just disable its watchers(?) in some service provider)

@briggsm
Copy link

briggsm commented Oct 12, 2024

Hmm, interesting, yes adding:

TELESCOPE_ENABLED=false

to .env file, causes the issue not to arise. Hope that piece of information helps you debug. Seems something to do with 3.8.5 and Telescope not working so well together? I assume this is still a 'bug', right? I would still like to be able to use Telescope if possible with 3.8.5.

Thank you for looking into this.

@stancl
Copy link
Member

stancl commented Oct 12, 2024

Some issues with the Telescope queue observer logic unserializing model payloads for the tenant connection after the application context reverts to the central app were reported before 3.8.5. I haven't had the time to look for the cause of that (e.g. if something changed in Telescope recently) but it seems the way the queues worked in 3.8.4 made the Telescope logic more reliable, or at least flaky instead of immediately failing.

Would be curious to hear if others here are also using Telescope?

It seems there are too many moving parts here. The queue change in 3.8.5 was done based on two reports on our Discord that queue:restart signals can be missed by the workers if they remain in the tenant context.

Since then, I've had one report of broken queued jobs when injecting model instances that use the tenant connection and the event-related issues mentioned here, though they may have another cause like the Telescope thing.

In general I prefer if people just get exceptions like these and are forced to reconfigure some integration or even restructure their jobs to inject model IDs over instances (though again that except for one report I couldn't reproduce seems to be a non issue), rather than the queue worker silently missing critical logic changes during a deployment.

That said, if 3.8.5 broke queues in a wider way I think we'd have more reports by now. So for now I'll wait for a repro using pure Tenancy without additional tools like Telescope while tracking the Telescope integration separately (with a workaround likely being just disabling the queue observer, also see the related discussions on our Discord recently).

@briggsm
Copy link

briggsm commented Oct 12, 2024

Ok, makes sense. Here's a few more details I learned regarding Telescope:

If I enabled telescope in .env:

TELESCOPE_ENABLED=true

Then in config/telescope.php:
If I comment out JUST: Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),

2024-10-12 14:37:30 App\Notifications\UnreadMessageNotification .... RUNNING

(Note: the process above doesn't get "DONE" running)

and

[2024-10-12 14:37:30] local.ERROR: Database connection [tenant] not configured. {"exception":"[object] (InvalidArgumentException(code: 0): Database connection [tenant] not configured. at /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php:188)
[stacktrace]
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php(151): Illuminate\\Database\\DatabaseManager->configuration()
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php(93): Illuminate\\Database\\DatabaseManager->makeConnection()
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1850): Illuminate\\Database\\DatabaseManager->connection()
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1816): Illuminate\\Database\\Eloquent\\Model::resolveConnection()
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(1574): Illuminate\\Database\\Eloquent\\Model->getConnection()
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(1492): Illuminate\\Database\\Eloquent\\Model->getDateFormat()
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(247): Illuminate\\Database\\Eloquent\\Model->asDateTime()
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(208): Illuminate\\Database\\Eloquent\\Model->addDateAttributesToArray()
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1664): Illuminate\\Database\\Eloquent\\Model->attributesToArray()
#9 [internal function]: Illuminate\\Database\\Eloquent\\Model->Illuminate\\Database\\Eloquent\\{closure}()
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/PreventsCircularRecursion.php(46): call_user_func()
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1663): Illuminate\\Database\\Eloquent\\Model->withoutRecursion()
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1695): Illuminate\\Database\\Eloquent\\Model->toArray()
#13 [internal function]: Illuminate\\Database\\Eloquent\\Model->jsonSerialize()
#14 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(146): json_encode()
#15 [internal function]: Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->Laravel\\Telescope\\Storage\\{closure}()
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Arr.php(605): array_map()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Collection.php(789): Illuminate\\Support\\Arr::map()
#18 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(145): Illuminate\\Support\\Collection->map()
#19 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(257): Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->Laravel\\Telescope\\Storage\\{closure}()
#20 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(144): Illuminate\\Support\\Collection->each()
#21 /var/www/html/vendor/laravel/telescope/src/Telescope.php(661): Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->store()
#22 [internal function]: Laravel\\Telescope\\Telescope::Laravel\\Telescope\\{closure}()
#23 /var/www/html/vendor/laravel/telescope/src/Telescope.php(286): call_user_func()
#24 /var/www/html/vendor/laravel/telescope/src/Telescope.php(653): Laravel\\Telescope\\Telescope::withoutRecording()
#25 /var/www/html/vendor/laravel/telescope/src/ListensForStorageOpportunities.php(110): Laravel\\Telescope\\Telescope::store()
#26 /var/www/html/vendor/laravel/telescope/src/ListensForStorageOpportunities.php(86): Laravel\\Telescope\\Telescope::storeIfDoneProcessingJob()
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(458): Laravel\\Telescope\\Telescope::Laravel\\Telescope\\{closure}()
#28 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(286): Illuminate\\Events\\Dispatcher->Illuminate\\Events\\{closure}()
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(266): Illuminate\\Events\\Dispatcher->invokeListeners()
#30 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(673): Illuminate\\Events\\Dispatcher->dispatch()
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(442): Illuminate\\Queue\\Worker->raiseAfterJobEvent()
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(390): Illuminate\\Queue\\Worker->process()
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(334): Illuminate\\Queue\\Worker->runJob()
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(141): Illuminate\\Queue\\Worker->runNextJob()
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(124): Illuminate\\Queue\\Console\\WorkCommand->runWorker()
#36 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Illuminate\\Queue\\Console\\WorkCommand->handle()
#37 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#38 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(95): Illuminate\\Container\\Util::unwrapIfClosure()
#39 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\Container\\BoundMethod::callBoundMethod()
#40 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(690): Illuminate\\Container\\BoundMethod::call()
#41 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(213): Illuminate\\Container\\Container->call()
#42 /var/www/html/vendor/symfony/console/Command/Command.php(279): Illuminate\\Console\\Command->execute()
#43 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(182): Symfony\\Component\\Console\\Command\\Command->run()
#44 /var/www/html/vendor/symfony/console/Application.php(1047): Illuminate\\Console\\Command->run()
#45 /var/www/html/vendor/symfony/console/Application.php(316): Symfony\\Component\\Console\\Application->doRunCommand()
#46 /var/www/html/vendor/symfony/console/Application.php(167): Symfony\\Component\\Console\\Application->doRun()
#47 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(197): Symfony\\Component\\Console\\Application->run()
#48 /var/www/html/artisan(35): Illuminate\\Foundation\\Console\\Kernel->handle()
#49 {main}
"}

If I comment out JUST: Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),

2024-10-12 14:40:08 App\Notifications\UnreadMessageNotification .... RUNNING
2024-10-12 14:40:08 App\Notifications\UnreadMessageNotification  81.40ms DONE

and

[2024-10-12 14:40:08] local.ERROR: Database connection [tenant] not configured. {"exception":"[object] (InvalidArgumentException(code: 0): Database connection [tenant] not configured. at /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php:188)
[stacktrace]
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php(151): Illuminate\\Database\\DatabaseManager->configuration()
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php(93): Illuminate\\Database\\DatabaseManager->makeConnection()
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1850): Illuminate\\Database\\DatabaseManager->connection()
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1816): Illuminate\\Database\\Eloquent\\Model::resolveConnection()
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(1574): Illuminate\\Database\\Eloquent\\Model->getConnection()
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(1492): Illuminate\\Database\\Eloquent\\Model->getDateFormat()
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(247): Illuminate\\Database\\Eloquent\\Model->asDateTime()
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(208): Illuminate\\Database\\Eloquent\\Model->addDateAttributesToArray()
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1664): Illuminate\\Database\\Eloquent\\Model->attributesToArray()
#9 [internal function]: Illuminate\\Database\\Eloquent\\Model->Illuminate\\Database\\Eloquent\\{closure}()
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/PreventsCircularRecursion.php(46): call_user_func()
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1663): Illuminate\\Database\\Eloquent\\Model->withoutRecursion()
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1695): Illuminate\\Database\\Eloquent\\Model->toArray()
#13 [internal function]: Illuminate\\Database\\Eloquent\\Model->jsonSerialize()
#14 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(146): json_encode()
#15 [internal function]: Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->Laravel\\Telescope\\Storage\\{closure}()
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Arr.php(605): array_map()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Collection.php(789): Illuminate\\Support\\Arr::map()
#18 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(145): Illuminate\\Support\\Collection->map()
#19 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(257): Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->Laravel\\Telescope\\Storage\\{closure}()
#20 /var/www/html/vendor/laravel/telescope/src/Storage/DatabaseEntriesRepository.php(144): Illuminate\\Support\\Collection->each()
#21 /var/www/html/vendor/laravel/telescope/src/Telescope.php(661): Laravel\\Telescope\\Storage\\DatabaseEntriesRepository->store()
#22 [internal function]: Laravel\\Telescope\\Telescope::Laravel\\Telescope\\{closure}()
#23 /var/www/html/vendor/laravel/telescope/src/Telescope.php(286): call_user_func()
#24 /var/www/html/vendor/laravel/telescope/src/Telescope.php(653): Laravel\\Telescope\\Telescope::withoutRecording()
#25 /var/www/html/vendor/laravel/telescope/src/ListensForStorageOpportunities.php(110): Laravel\\Telescope\\Telescope::store()
#26 /var/www/html/vendor/laravel/telescope/src/ListensForStorageOpportunities.php(86): Laravel\\Telescope\\Telescope::storeIfDoneProcessingJob()
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(458): Laravel\\Telescope\\Telescope::Laravel\\Telescope\\{closure}()
#28 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(286): Illuminate\\Events\\Dispatcher->Illuminate\\Events\\{closure}()
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(266): Illuminate\\Events\\Dispatcher->invokeListeners()
#30 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(673): Illuminate\\Events\\Dispatcher->dispatch()
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(442): Illuminate\\Queue\\Worker->raiseAfterJobEvent()
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(390): Illuminate\\Queue\\Worker->process()
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(334): Illuminate\\Queue\\Worker->runJob()
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(141): Illuminate\\Queue\\Worker->runNextJob()
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(124): Illuminate\\Queue\\Console\\WorkCommand->runWorker()
#36 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Illuminate\\Queue\\Console\\WorkCommand->handle()
#37 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#38 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(95): Illuminate\\Container\\Util::unwrapIfClosure()
#39 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\Container\\BoundMethod::callBoundMethod()
#40 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(690): Illuminate\\Container\\BoundMethod::call()
#41 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(213): Illuminate\\Container\\Container->call()
#42 /var/www/html/vendor/symfony/console/Command/Command.php(279): Illuminate\\Console\\Command->execute()
#43 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(182): Symfony\\Component\\Console\\Command\\Command->run()
#44 /var/www/html/vendor/symfony/console/Application.php(1047): Illuminate\\Console\\Command->run()
#45 /var/www/html/vendor/symfony/console/Application.php(316): Symfony\\Component\\Console\\Application->doRunCommand()
#46 /var/www/html/vendor/symfony/console/Application.php(167): Symfony\\Component\\Console\\Application->doRun()
#47 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(197): Symfony\\Component\\Console\\Application->run()
#48 /var/www/html/artisan(35): Illuminate\\Foundation\\Console\\Kernel->handle()
#49 {main}
"} 

If I comment out BOTH: Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true), and Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),

No exceptions, just the expected:

2024-10-12 14:43:56 App\Notifications\UnreadMessageNotification .... RUNNING
2024-10-12 14:43:56 App\Notifications\UnreadMessageNotification  68.18ms DONE

@hapidjus
Copy link

hapidjus commented Oct 23, 2024

Geting the same error here after upgrading. Turning of Telescope helps.
Edit:
I have tracked down the change that causes this in our codebase. ed52c48#diff-d2557c1097c40e15ec7fc42979d9d8133351c52d2c0e5ba6fb89d2e78caffbdaR74

Bringing back the conditional for $runningTests makes it work again. Just speculating, but maybe Telescope is abusing the testing ENV somehow?

@stancl
Copy link
Member

stancl commented Oct 23, 2024

Just read the above. Support for Telescope observing tenant jobs has been flaky before too (due to how it unserializes the job payloads), it's just more reliably erroring out now. It may be possible to make the integration work, I just don't have the time to look into it now.

@jetwes
Copy link
Author

jetwes commented Oct 23, 2024

Just to clarify: I never used telescope at all. I set up a minimal demo - but in that it worked. There has to be some sort of setup which wont work...

@stancl
Copy link
Member

stancl commented Oct 23, 2024

Yeah I can see some existing logic being broken without Telescope, but haven't been able to reproduce it myself. Once I have some simple reproduction repo I'll see what's broken and how we can fix that.

@hapidjus
Copy link

Yeah sorry about that, I've sent a (janky) PR to telescope that fixes my problem laravel/telescope#1539

@stancl
Copy link
Member

stancl commented Oct 25, 2024

Looks good, since it's addressing an existing Telescope bug there's a better chance it may get merged over just implementing a fix specifically for this package.

Perhaps in the future, I could try to come up a more general solution for making tenant models serializable.

@hapidjus
Copy link

Unfortunately, the merged PR only catches the ModelNotFoundException, so I’ll need to create another PR to address this. I just need to make a minimal reproduction to support the case for catching additional exceptions and errors

@stancl
Copy link
Member

stancl commented Oct 30, 2024

From the stack traces posted above, it seems the thrown exception is InvalidArgumentException? Seems way too generic here. The ideal solution would probably be adding a new exception to laravel/framework that'd be thrown in this scenario, but I'm not sure how willing they'd be to make that change.

The only other approach I can think of that's still limited in catch scope would be catching InvalidArgumentException and checking that the exception message contains "Database connection [...] not configured".

@hapidjus
Copy link

hapidjus commented Oct 30, 2024

Yes the exception is pretty strange. Agree that its unlikely that a new exception will get included.

Its kind of frustrating as the unserialize method is only used for getting the batch_id which we can get with preg_match instead. The rest of the unserialzied data is discarded.

I guess I could just make my own JobWatcher and override getBatchId there, but I'd rather fix it at the "source"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants