Trying to Dispatch Jobs via Tinker with Laravel and SQLite
I've been learning Laravel queues and jobs. While creating some jobs I wanted a quick way to test by executing the job. I just want to see it run. There wasn't a super clear path for me here so my first thought was let's just quickly create a one off controller action. To replay that job over again I just had to refresh my browser. Not great, super odd, but also not the end of the world. Yes, of course I could write some actual tests (and I will), but I really just want a way to execute services and such in my app ad hoc.
public function testing_this_job()
{
$recipe = Recipe::find(5);
ProcessRecipeImport::dispatch($recipe);
}
Yeah it works, but is _super_ clunky. Let's try tinker.
php artisan tinker
$recipe = Recipe::find(5);
[!] Aliasing ‘Recipe’ to ‘App\Models\Recipe’ for this Tinker session.
Illuminate\Database\QueryException SQLSTATE[HY000]: General error: 10 disk I/O error (Connection: sqlite, SQL: select * from “recipes” where “recipes”.“id” = 17 limit 1).
Hmm that didn't work. WHY? The SQLite database does exist and does work as I can view data in my app when I run the server. I can also connect to the db via DataGrip and query data. I've tried closing all connections. Still cannot read from tables. Do I need to somehow load db configuration manually when I start a tinker session? At this point I've searched the internet for answers and tried to ChatGPT my way through this to no avail. Totally stuck.
For being the default database connection I would expect this to just work out of the box.
Hours of searching and I have come to realize that SQLite is maybe not great and shouldn't be used even for development? I dunno, it's probably fine, but there is _something_ with tinker and psysh that is preventing me from interacting with the database. It smells like the db connection is already opened and when I try to connect I get the error, because of the existing connection. When I connect to the console, then run from my terminal:
$ sudo lsof | grep database.sqlite
php 74738 roylindauer 7u REG 1,18 339968 65235486 /Users/roylindauer/code/laravel-app/database/database-copy.sqlite
It's open. So does that mean when I try to query a record it tries to open another connection which fails? Seems that way. Just not sure. And i'm growing impatient. It also fails on a brand new app:
$ composer create-project laravel/laravel:^11.0 laravel-testing-sqlite
$ cd laravel-testing-sqlite
$ php artisan tinker
Psy Shell v0.12.3 (PHP 8.3.4 — cli) by Justin Hileman
> User::all()
[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
Illuminate\Database\QueryException SQLSTATE[HY000]: General error: 10 disk I/O error (Connection: sqlite, SQL: select * from “users”).
>
This has to be a MacOS thing. Or maybe an Apple Silicon thing? I kinda want to try on Ubuntu next. Other things it could be: the version of SQLite I am running? Something with my homebrew setup? I did install PHP 8.3.4 via ASDF maybe the answer lies there.
Next I tried PHP 8.2.17. I updated my `.tool-versions` file to use PHP 8.2.17 then executed `asdf install`. I was asked to install command line developer tools, which should have already been installed. That's wild. Doing that I guess, then installing PHP 8.2.17 again. No matter I am still prompted to install command line developer tools, which are already installed. I tried a new terminal session. I tried rebooting. No success.
At this point I am going to do two things: Abandon SQLite, and use MySQL and Docker.
I am a little disappointed I couldn't figure the issue out with SQLite.
Running the database through MySQL and Docker and this all works fine! I can finally query my database! So back to my initial problem. How do I dispatch jobs through tinker?
$recipe = Recipe::find(5);
ProcessRecipeImport::dispatch($recipe);
This actually does not work! The dispatch helper function depends on garbage collection.
The dispatch helper function and dispatch method on the Dispatchable class depends on garbage collection to place the job on the queue. Therefore, when using tinker, you should use Bus::dispatch or Queue::push to dispatch jobs.
So the correct way to quickly dispatch my job and let me get back to tinkering is:
$recipe = Recipe::find(5);
\Bus::dispatch(new App\Jobs\ProcessRecipeImport($recipe));
Wonderful! Tinker is awesome!