* fix: give Pinterest video processing more time and retry on timeout A valid ~54s video pin failed after ~90s of polling while Pinterest was still processing. Extend the poll window to ~5 minutes and treat timeout as platform unavailable so PublishToSocialPlatform reschedules instead of failing the post on the first attempt. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: use Laravel Sleep for Pinterest media processing polls Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: inline Pinterest video processing poll constants Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: map Pinterest media upload statuses to an enum Use the official MediaUploadStatus values (registered, processing, succeeded, failed) instead of comparing raw strings in the publisher. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: trim Pinterest media processing docblock * fix: cap platform-unavailable retries and recover stuck retrying posts Stop infinite reschedules after 6 attempts with a user-safe failure message, keep technical detail in error_context, recover Retrying platforms in social:recover-stuck-posts, and drop unused isTerminal(). Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: remove unused failedCount in RecoverStuckPosts Co-authored-by: Cursor <cursoragent@cursor.com> * fix: skip final Pinterest poll sleep and localize recover timeout Co-authored-by: Cursor <cursoragent@cursor.com> * fix: raise publish job timeout headroom and ignore already-failed platforms Give social publish jobs 15 minutes so Pinterest media polling fits under the worker limit, bump Horizon/redis retry_after above that timeout, and skip handle/failed when the platform is already Failed so delayed jobs cannot revive posts recovered by social:recover-stuck-posts. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: restore social-publishing and ai-assistant horizon supervisors Co-authored-by: Cursor <cursoragent@cursor.com> * fix: harden Pinterest 401 handling, unique publish jobs, and recover JSON Treat media-status 401 as TokenExpired, make PublishToSocialPlatform unique per platform+attempt so retries still queue, and persist recover error_context via Eloquent casts instead of manual json_encode. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: mass-update stuck post platforms without per-row each Eloquent query updates already bind JSON arrays correctly here, so one UPDATE is enough — no manual json_encode and no N model writes. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: simplify Pinterest media processing poll loop Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: simplify publish job retry and terminal status checks Co-authored-by: Cursor <cursoragent@cursor.com> * fix: do not finalize posts while platforms are still retrying Co-authored-by: Cursor <cursoragent@cursor.com> * test: cover Pinterest timeout, unique jobs, and recover edge cases Co-authored-by: Cursor <cursoragent@cursor.com> * fix: retry Pinterest media poll on connection errors and tighten tests Co-authored-by: Cursor <cursoragent@cursor.com> * fix: remove ineffective TypeError import that breaks CI Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
320 lines
9.7 KiB
PHP
320 lines
9.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Enums\SocialAccount\Platform;
|
|
use Illuminate\Support\Str;
|
|
|
|
return [
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Horizon Name
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This name appears in notifications and in the Horizon UI. Unique names
|
|
| can be useful while running multiple instances of Horizon within an
|
|
| application, allowing you to identify the Horizon you're viewing.
|
|
|
|
|
*/
|
|
|
|
'name' => env('HORIZON_NAME'),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Horizon Domain
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This is the subdomain where Horizon will be accessible from. If this
|
|
| setting is null, Horizon will reside under the same domain as the
|
|
| application. Otherwise, this value will serve as the subdomain.
|
|
|
|
|
*/
|
|
|
|
'domain' => env('HORIZON_DOMAIN'),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Horizon Allowed Emails
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This is a comma-separated list of email addresses that are allowed to
|
|
| access Horizon in non-local environments. Leave empty to deny all.
|
|
|
|
|
*/
|
|
|
|
'allowed_emails' => env('HORIZON_ALLOWED_EMAILS', ''),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Horizon Path
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This is the URI path where Horizon will be accessible from. Feel free
|
|
| to change this path to anything you like. Note that the URI will not
|
|
| affect the paths of its internal API that aren't exposed to users.
|
|
|
|
|
*/
|
|
|
|
'path' => env('HORIZON_PATH', 'horizon'),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Horizon Redis Connection
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This is the name of the Redis connection where Horizon will store the
|
|
| meta information required for it to function. It includes the list
|
|
| of supervisors, failed jobs, job metrics, and other information.
|
|
|
|
|
*/
|
|
|
|
'use' => 'default',
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Horizon Redis Prefix
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This prefix will be used when storing all Horizon data in Redis. You
|
|
| may modify the prefix when you are running multiple installations
|
|
| of Horizon on the same server so that they don't have problems.
|
|
|
|
|
*/
|
|
|
|
'prefix' => env(
|
|
'HORIZON_PREFIX',
|
|
Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:'
|
|
),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Horizon Route Middleware
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| These middleware will get attached onto each Horizon route, giving you
|
|
| the chance to add your own middleware to this list or change any of
|
|
| the existing middleware. Or, you can simply stick with this list.
|
|
|
|
|
*/
|
|
|
|
'middleware' => ['web'],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Queue Wait Time Thresholds
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This option allows you to configure when the LongWaitDetected event
|
|
| will be fired. Every connection / queue combination may have its
|
|
| own, unique threshold (in seconds) before this event is fired.
|
|
|
|
|
*/
|
|
|
|
'waits' => [
|
|
'redis:default' => 60,
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Job Trimming Times
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Here you can configure for how long (in minutes) you desire Horizon to
|
|
| persist the recent and failed jobs. Typically, recent jobs are kept
|
|
| for one hour while all failed jobs are stored for an entire week.
|
|
|
|
|
*/
|
|
|
|
'trim' => [
|
|
'recent' => 60,
|
|
'pending' => 60,
|
|
'completed' => 60,
|
|
'recent_failed' => 10080,
|
|
'failed' => 10080,
|
|
'monitored' => 10080,
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Silenced Jobs
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Silencing a job will instruct Horizon to not place the job in the list
|
|
| of completed jobs within the Horizon dashboard. This setting may be
|
|
| used to fully remove any noisy jobs from the completed jobs list.
|
|
|
|
|
*/
|
|
|
|
'silenced' => [
|
|
// App\Jobs\ExampleJob::class,
|
|
],
|
|
|
|
'silenced_tags' => [
|
|
// 'notifications',
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Metrics
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Here you can configure how many snapshots should be kept to display in
|
|
| the metrics graph. This will get used in combination with Horizon's
|
|
| `horizon:snapshot` schedule to define how long to retain metrics.
|
|
|
|
|
*/
|
|
|
|
'metrics' => [
|
|
'trim_snapshots' => [
|
|
'job' => 24,
|
|
'queue' => 24,
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Fast Termination
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| When this option is enabled, Horizon's "terminate" command will not
|
|
| wait on all of the workers to terminate unless the --wait option
|
|
| is provided. Fast termination can shorten deployment delay by
|
|
| allowing a new instance of Horizon to start while the last
|
|
| instance will continue to terminate each of its workers.
|
|
|
|
|
*/
|
|
|
|
'fast_termination' => false,
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Memory Limit (MB)
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| This value describes the maximum amount of memory the Horizon master
|
|
| supervisor may consume before it is terminated and restarted. For
|
|
| configuring these limits on your workers, see the next section.
|
|
|
|
|
*/
|
|
|
|
'memory_limit' => 64,
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Queue Worker Configuration
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Here you may define the queue worker settings used by your application
|
|
| in all environments. These supervisors and settings handle all your
|
|
| queued jobs and will be provisioned by Horizon during deployment.
|
|
|
|
|
*/
|
|
|
|
'defaults' => [
|
|
'supervisor-1' => [
|
|
'connection' => 'redis',
|
|
'queue' => ['default', 'posthog', 'broadcasts'],
|
|
'balance' => 'auto',
|
|
'autoScalingStrategy' => 'time',
|
|
'maxProcesses' => 1,
|
|
'maxTime' => 0,
|
|
'maxJobs' => 0,
|
|
'memory' => 128,
|
|
'tries' => 1,
|
|
'timeout' => 630,
|
|
'nice' => 0,
|
|
],
|
|
|
|
'social-publishing' => [
|
|
'connection' => 'redis',
|
|
'queue' => Platform::allQueues(),
|
|
'balance' => 'auto',
|
|
'autoScalingStrategy' => 'time',
|
|
'minProcesses' => 1,
|
|
'maxProcesses' => 3,
|
|
'timeout' => 930,
|
|
'maxTime' => 0,
|
|
'maxJobs' => 0,
|
|
'memory' => 256,
|
|
'tries' => 1,
|
|
'nice' => 0,
|
|
],
|
|
|
|
'ai-assistant' => [
|
|
'connection' => 'redis',
|
|
'queue' => ['ai'],
|
|
'balance' => 'auto',
|
|
'autoScalingStrategy' => 'time',
|
|
'minProcesses' => 1,
|
|
'maxProcesses' => 2,
|
|
'timeout' => 930,
|
|
'maxTime' => 0,
|
|
'maxJobs' => 0,
|
|
'memory' => 512,
|
|
'tries' => 1,
|
|
'nice' => 0,
|
|
],
|
|
|
|
'automations' => [
|
|
'connection' => 'redis',
|
|
'queue' => ['automations'],
|
|
'balance' => 'auto',
|
|
'autoScalingStrategy' => 'time',
|
|
'minProcesses' => 1,
|
|
'maxProcesses' => 3,
|
|
'timeout' => 630,
|
|
'maxTime' => 0,
|
|
'maxJobs' => 0,
|
|
'memory' => 256,
|
|
'tries' => 1,
|
|
'nice' => 0,
|
|
],
|
|
],
|
|
|
|
'environments' => [
|
|
'production' => [
|
|
'supervisor-1' => [
|
|
'maxProcesses' => 10,
|
|
'balanceMaxShift' => 1,
|
|
'balanceCooldown' => 3,
|
|
],
|
|
|
|
'social-publishing' => [
|
|
'maxProcesses' => 10,
|
|
'balanceMaxShift' => 1,
|
|
'balanceCooldown' => 3,
|
|
],
|
|
|
|
'ai-assistant' => [
|
|
'maxProcesses' => 5,
|
|
'balanceMaxShift' => 1,
|
|
'balanceCooldown' => 3,
|
|
],
|
|
|
|
'automations' => [
|
|
'maxProcesses' => 5,
|
|
'balanceMaxShift' => 1,
|
|
'balanceCooldown' => 3,
|
|
],
|
|
],
|
|
|
|
'local' => [
|
|
'supervisor-1' => [
|
|
'maxProcesses' => 3,
|
|
],
|
|
|
|
'social-publishing' => [
|
|
'maxProcesses' => 3,
|
|
],
|
|
|
|
'ai-assistant' => [
|
|
'maxProcesses' => 2,
|
|
],
|
|
|
|
'automations' => [
|
|
'maxProcesses' => 2,
|
|
],
|
|
],
|
|
],
|
|
];
|