Zdarzenie po publikacji, kolejka, adres w bazie.
W Laravelu naturalnym miejscem jest kolejka: publikacja wpisu wrzuca zadanie, zadanie woła API i zapisuje adres. Strona nigdy nie czeka na render, a nieudany render sam się ponowi.
app/Jobs/GenerateOgImage.php
final class GenerateOgImage implements ShouldQueue
{
use Queueable;
public int $tries = 3;
public function __construct(private readonly int $postId) {}
public function handle(): void
{
$post = Post::findOrFail($this->postId);
$response = Http::withToken(config('services.imageapi.key'))
->timeout(20)
->post('https://imageapi.dev/v1/images?wait=true', [
'template' => 'blog-og',
'locale' => 'en',
'modifications' => [
'title' => $post->title,
'author' => $post->author->name,
'date' => $post->published_at->toDateString(),
'reading_time' => $post->reading_minutes,
'site' => config('app.domain'),
],
])
->throw();
$post->update(['og_image' => $response->json('url')]);
}
}
// Dispatch it on publish:
// GenerateOgImage::dispatch($post->id)->afterCommit();
`afterCommit()` jest tu istotne: bez niego zadanie może wystartować, zanim transakcja zapisująca wpis się zatwierdzi, i `findOrFail` wywali się na nieistniejącym rekordzie.
Z ?wait=true czekasz na gotowy obrazek w tym samym połączeniu — zwykle około sekundy.
{
"id": "img_01m08s3ez1zcv28h335g9923bw",
"status": "completed",
"url": "https://cdn.imageapi.dev/renders/img_01m08s3ez1zcv28h335g9923bw.png",
"duration_ms": 912
}
Sto obrazków miesięcznie za darmo, potem $9 za dwa tysiące. Ten sam wpis wyrenderowany drugi raz zwraca istniejący adres i nie zużywa limitu — więc przebudowanie strony nic nie kosztuje.