Skip to content

Conversation

@andrasbacsai
Copy link
Member

@andrasbacsai andrasbacsai commented Nov 10, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Configurable timeout for scheduled tasks (60–3600 seconds, default 300)
    • Intelligent job retry logic with automatic backoff intervals
    • Enhanced execution tracking with duration and retry metrics
  • Improvements

    • Better error handling and logging for failed jobs
    • Team notifications for backup failures
    • Optimized Redis cleanup during system restarts
  • Documentation

    • New testing guide for scheduled task management

Fixes

- Add retry configuration to CoolifyTask (3 tries, 600s timeout)
- Add retry configuration to ScheduledTaskJob (3 tries, configurable timeout)
- Add retry configuration to DatabaseBackupJob (2 tries)
- Implement exponential backoff for all jobs (30s, 60s, 120s intervals)
- Add failed() handlers with comprehensive error logging to scheduled-errors channel
- Add execution tracking: started_at, retry_count, duration (decimal), error_details
- Add configurable timeout field to scheduled tasks (60-3600s, default 300s)
- Update UI to include timeout configuration in task creation/editing forms
- Increase ScheduledJobManager lock expiration from 60s to 90s for high-load environments
- Implement safe queue cleanup with restart vs runtime modes
  - Restart mode: aggressive cleanup (marks all processing jobs as failed)
  - Runtime mode: conservative cleanup (only marks jobs >12h as failed, skips deployments)
- Add cleanup:redis --restart flag for system startup
- Integrate cleanup into Dev.php init() for development environment
- Increase scheduled-errors log retention from 7 to 14 days
- Create comprehensive test suite (unit and feature tests)
- Add TESTING_GUIDE.md with manual testing instructions

Fixes issues with jobs failing after single attempt and "attempted too many times" errors
@andrasbacsai
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 2025

Walkthrough

The PR adds retry and timeout handling to scheduled task jobs (CoolifyTask, ScheduledTaskJob, DatabaseBackupJob) with configurable backoff strategies, introduces aggressive stuck job cleanup on startup via a new --restart flag in CleanupRedis, extends execution tracking with timestamp and retry count columns, and updates UI components and configuration to support timeout management.

Changes

Cohort / File(s) Summary
Scheduled Task Job Configuration
app/Jobs/CoolifyTask.php, app/Jobs/ScheduledTaskJob.php, app/Jobs/DatabaseBackupJob.php
Added public properties for retry behavior (tries, maxExceptions, timeout) and backoff() methods returning staggered retry intervals. Implemented failed() handlers to log errors to scheduled-errors channel, update task/backup logs with error details, and notify teams on permanent failure.
Job Middleware & Manager
app/Jobs/ScheduledJobManager.php
Increased middleware lock expiry from 60 to 90 seconds with updated comment.
Redis Cleanup & Startup
app/Console/Commands/CleanupRedis.php, app/Console/Commands/Dev.php, app/Console/Commands/Init.php
Added --restart option to CleanupRedis command signature. Implemented cleanupStuckJobs() private method with two modes: restart (aggressive, marks all processing jobs failed) and runtime (conservative, skips long-running jobs, fails if > 12 hours). Dev.php and Init.php now invoke cleanup with --restart and --clear-locks flags.
Scheduled Task Model & Execution Tracking
app/Models/ScheduledTask.php, app/Models/ScheduledTaskExecution.php
Added casts() method to ScheduledTask for enabled (boolean) and timeout (integer). Added casts() method to ScheduledTaskExecution for started_at and finished_at (datetime), retry_count (integer), and duration (decimal:2).
Scheduled Task UI Components
app/Livewire/Project/Shared/ScheduledTask/Add.php, app/Livewire/Project/Shared/ScheduledTask/Show.php
Added public $timeout property (default 300) with validation rules (required integer, 60–3600 range). Property synced to/from model on save/load.
Scheduled Task Views
resources/views/livewire/project/shared/scheduled-task/add.blade.php, resources/views/livewire/project/shared/scheduled-task/show.blade.php
Added numeric input fields for timeout (seconds) with helper text and range constraints (60–3600).
Database Migrations
database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php, database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
Added timeout column (integer, default 300) to scheduled_tasks table. Added started_at, retry_count, duration, and error_details columns to scheduled_task_executions table with appropriate types and defaults.
Logging Configuration
config/logging.php
Updated scheduled-errors channel: level changed from debug to warning; retention changed from 7 to 14 days.
Service Templates
templates/service-templates-latest.json, templates/service-templates.json
Updated service template metadata: changed category and tags for multiple entries to reflect analytics classification; modified compose configurations for affected services.
Test Coverage
tests/Feature/CoolifyTaskRetryTest.php, tests/Unit/ScheduledJobsRetryConfigTest.php
Added feature tests validating CoolifyTask dispatch and retry properties (tries, maxExceptions, timeout, backoff). Added unit tests using Reflection to verify retry configuration and default values for CoolifyTask, ScheduledTaskJob, and DatabaseBackupJob.
Documentation
TESTING_GUIDE.md
Added new testing guide documenting testing procedures for scheduled tasks improvements, including test commands, manual testing workflows, monitoring, verification steps, and troubleshooting guidance.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Dev as Dev Command
    participant Redis as Redis<br/>(via CleanupRedis)
    participant Queue as Job Queue
    participant Job as Job Handler
    participant Log as Logger
    
    User->>Dev: Run startup
    Dev->>Redis: cleanup:redis --restart --clear-locks
    Redis->>Redis: cleanupStuckJobs()<br/>(restart mode)
    Redis->>Redis: Mark all processing/reserved<br/>jobs as failed
    note over Redis: Log cleanup summary
    
    Dev->>Queue: Initialize queue workers
    Note over Queue: Ready for new jobs
    
    User->>Queue: Dispatch ScheduledTaskJob
    Queue->>Job: Execute job
    alt Job succeeds
        Job->>Job: Record finished_at,<br/>duration in task_log
        Job-->>User: Success
    else Job fails
        Job->>Log: Log error to<br/>scheduled-errors
        Job->>Job: Update task_log with<br/>error_details, retry_count
        Job->>Job: Call backoff()<br/>for retry interval
        Note over Job: Retry with [30, 60, 120]s<br/>intervals (up to 3 times)
        alt Retries exhausted
            Job->>Job: Call failed()
            Job->>Log: Log permanent failure
            Job->>Job: Update finished_at,<br/>notify team
            Job-->>User: Permanent failure
        else Retry succeeds
            Job-->>User: Success after retry
        end
    end
Loading
sequenceDiagram
    participant Admin as Admin
    participant UI as Scheduled Task UI
    participant Component as Livewire Component
    participant Model as ScheduledTask Model
    
    Admin->>UI: Create/Edit Task
    Admin->>UI: Set timeout field<br/>(60–3600 seconds)
    note over UI: Validation enforced<br/>in component
    
    Admin->>UI: Save task
    Component->>Component: Validate timeout<br/>integer, range check
    alt Validation passes
        Component->>Model: Persist timeout<br/>to database
        Model->>Model: Cast as integer
        Component->>Admin: Show success
    else Validation fails
        Component->>Admin: Show error message
    end
    
    Admin->>UI: View existing task
    Component->>Model: Load timeout from DB
    Model->>Component: Return timeout (cast int,<br/>default 300 if null)
    UI->>Admin: Display timeout field<br/>with loaded value
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • app/Console/Commands/CleanupRedis.php — New cleanupStuckJobs() method with two operational modes (restart vs. runtime) and dual-path logic (dry-run vs. live); Redis HSET mutations and job failure marking need verification.
  • app/Jobs/ScheduledTaskJob.php — Extensive lifecycle tracking with started_at, retry_count, finished_at, and duration in task_log; interaction between failed() handler and Laravel's retry mechanism should be verified.
  • Job failure handlers across CoolifyTask, ScheduledTaskJob, DatabaseBackupJob — Ensure proper error logging, notification dispatch, and state persistence; verify that rethrow behavior correctly triggers Laravel's retry logic.
  • Database migrations (2025_11_09_000002) — Schema changes to scheduled_task_executions (added columns, types, nullability) should be validated for backward compatibility and index impact.
  • Service template updates (templates/*) — Metadata changes (category, tags, compose configs) appear to have encoding/formatting anomalies in the diff; manual verification of template integrity recommended.

Possibly related PRs

Poem

🐰 A rabbit's ode to resilience and care:

With timeouts set and retries fair,
Jobs bounce back through the morning air.
Stuck tasks cleaned at every dawn,
Through redis dust, we carry on.
Tracking each attempt with pride—
This job queue dances far and wide! ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.38% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ⚠️ Warning The pull request has no description provided by the author. The required template sections (Changes, Issues, and Submit Checklist) are completely absent. Add a comprehensive PR description following the template, including: (1) Changes section listing all modifications, (2) Issues section with related issue/discussion links, (3) confirmation of testing and backwards compatibility considerations.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: enhanced retry and timeout features for scheduled tasks, which aligns with the comprehensive improvements across multiple job classes and configuration files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch improve-scheduled-tasks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/Jobs/ScheduledTaskJob.php (1)

44-45: Prevent fatal logging when server isn't initialized

$this->server is typed as non-nullable and only assigned after we hit the container lookup. If anything throws before that assignment (e.g. the execution insert or retrieving the destination), the catch/failed handlers will try to read $this->server and PHP will raise “Typed property ... must not be accessed before initialization,” losing the original error. Make the property nullable (same for the log reads) so we can safely log early failures.

-    public Server $server;
+    public ?Server $server = null;
@@
-                'server' => $this->server->name ?? 'unknown',
+                'server' => $this->server?->name ?? 'unknown',
@@
-            'server' => $this->server->name ?? 'unknown',
+            'server' => $this->server?->name ?? 'unknown',
app/Jobs/DatabaseBackupJob.php (1)

47-50: Initialize optional dependencies before failed() logging

$server and $database are declared as non-nullable typed properties, but failures can happen before they’re assigned (e.g. missing relations or errors pulling metadata). When failed() runs it accesses them, which will trigger “Typed property … must not be accessed before initialization” and mask the real failure. Make them nullable with a default null so the logging path stays safe.

-    public Server $server;
-
-    public StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database;
+    public ?Server $server = null;
+
+    public StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase|null $database = null;
🧹 Nitpick comments (1)
app/Models/ScheduledTask.php (1)

13-13: Consider defining explicit $fillable for mass assignment protection.

Using $guarded = [] allows all attributes to be mass-assigned. Consider defining an explicit $fillable array to be more restrictive and secure.

Based on coding guidelines.

Apply this diff to add explicit fillable attributes:

-    protected $guarded = [];
+    protected $fillable = [
+        'name',
+        'command',
+        'frequency',
+        'container',
+        'enabled',
+        'timeout',
+        'application_id',
+        'service_id',
+        'team_id',
+    ];
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 649dd02 and b22e79c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (21)
  • TESTING_GUIDE.md (1 hunks)
  • app/Console/Commands/CleanupRedis.php (3 hunks)
  • app/Console/Commands/Dev.php (1 hunks)
  • app/Console/Commands/Init.php (1 hunks)
  • app/Jobs/CoolifyTask.php (2 hunks)
  • app/Jobs/DatabaseBackupJob.php (3 hunks)
  • app/Jobs/ScheduledJobManager.php (1 hunks)
  • app/Jobs/ScheduledTaskJob.php (4 hunks)
  • app/Livewire/Project/Shared/ScheduledTask/Add.php (3 hunks)
  • app/Livewire/Project/Shared/ScheduledTask/Show.php (2 hunks)
  • app/Models/ScheduledTask.php (1 hunks)
  • app/Models/ScheduledTaskExecution.php (1 hunks)
  • config/logging.php (1 hunks)
  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php (1 hunks)
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php (1 hunks)
  • resources/views/livewire/project/shared/scheduled-task/add.blade.php (1 hunks)
  • resources/views/livewire/project/shared/scheduled-task/show.blade.php (1 hunks)
  • templates/service-templates-latest.json (3 hunks)
  • templates/service-templates.json (3 hunks)
  • tests/Feature/CoolifyTaskRetryTest.php (1 hunks)
  • tests/Unit/ScheduledJobsRetryConfigTest.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (25)
app/Jobs/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)

Queueable background work should be implemented as Jobs under app/Jobs; Actions may expose asJob to dispatch

app/Jobs/**/*.php: Queue jobs should implement ShouldQueue and define retry strategy (tries, maxExceptions, backoff)
Queue jobs must handle success/failure state updates and broadcast corresponding events; implement failed(Throwable) for final failure handling

Queue jobs should update status, wrap external calls in try/catch, set failure status on exceptions, and rethrow

Files:

  • app/Jobs/ScheduledJobManager.php
  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • app/Jobs/DatabaseBackupJob.php
app/Jobs/*.php

📄 CodeRabbit inference engine (.cursor/rules/deployment-architecture.mdc)

Implement background deployment, monitoring, backup, and notification work as Laravel Job classes under app/Jobs

Files:

  • app/Jobs/ScheduledJobManager.php
  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • app/Jobs/DatabaseBackupJob.php
**/*.php

📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)

**/*.php: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions

**/*.php: Follow PSR-12 PHP coding standards across the codebase
Prefer eager loading and query optimization to prevent N+1 issues in database interactions
Use Laravel best practices for structure, services, and policies

**/*.php: Always use curly braces for control structures in PHP, even for single-line bodies
Use PHP 8 constructor property promotion in __construct() and avoid empty constructors
Always declare explicit return types for functions and methods; add appropriate parameter type hints
Prefer PHPDoc blocks over inline comments; only add inline code comments for very complex logic
When documenting arrays, add useful array shape types in PHPDoc where appropriate
Enum case names should be TitleCase (e.g., FavoritePerson, Monthly)

Files:

  • app/Jobs/ScheduledJobManager.php
  • app/Models/ScheduledTaskExecution.php
  • config/logging.php
  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • app/Models/ScheduledTask.php
  • app/Console/Commands/CleanupRedis.php
  • tests/Feature/CoolifyTaskRetryTest.php
  • app/Console/Commands/Dev.php
  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • resources/views/livewire/project/shared/scheduled-task/show.blade.php
  • app/Console/Commands/Init.php
  • app/Livewire/Project/Shared/ScheduledTask/Show.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
  • tests/Unit/ScheduledJobsRetryConfigTest.php
  • app/Livewire/Project/Shared/ScheduledTask/Add.php
  • app/Jobs/DatabaseBackupJob.php
  • resources/views/livewire/project/shared/scheduled-task/add.blade.php
app/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)

Use database transactions to group related write operations for consistency in services/controllers/jobs

Files:

  • app/Jobs/ScheduledJobManager.php
  • app/Models/ScheduledTaskExecution.php
  • app/Models/ScheduledTask.php
  • app/Console/Commands/CleanupRedis.php
  • app/Console/Commands/Dev.php
  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • app/Console/Commands/Init.php
  • app/Livewire/Project/Shared/ScheduledTask/Show.php
  • app/Livewire/Project/Shared/ScheduledTask/Add.php
  • app/Jobs/DatabaseBackupJob.php
app/Jobs/**

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Implement background jobs under app/Jobs

Files:

  • app/Jobs/ScheduledJobManager.php
  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • app/Jobs/DatabaseBackupJob.php
app/Models/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)

Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)

app/Models/**/*.php: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)

app/Models/**/*.php: Define Eloquent relationships using proper relationship methods with return type hints
Prefer Eloquent ORM and relationships over raw queries or DB:: calls
Prevent N+1 queries by using eager loading when appropriate
When creating new models, also create useful factories and seeders

Files:

  • app/Models/ScheduledTaskExecution.php
  • app/Models/ScheduledTask.php
app/Models/**

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Place domain models under app/Models

Files:

  • app/Models/ScheduledTaskExecution.php
  • app/Models/ScheduledTask.php
app/Models/*.php

📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)

app/Models/*.php: When adding new database columns, update the model's $fillable array to allow mass assignment (e.g., for Model::create() and $model->update())
Use UUID primary keys via HasUuids for distributed systems
Enable soft deletes on models that require audit trails using SoftDeletes
Log model activity using the Spatie LogsActivity trait where auditing is required
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) for navigable associations used by queries and eager loading

Files:

  • app/Models/ScheduledTaskExecution.php
  • app/Models/ScheduledTask.php
config/*.php

📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)

Keep application settings in Laravel config files under config/ and load them via config()

Application configuration should reside in config/*.php files

Files:

  • config/logging.php
database/migrations/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)

Create descriptive migrations with proper foreign keys, cascading deletes, indexes, and timestamps

database/migrations/**/*.php: When modifying a column in a migration, re-specify all previously defined attributes to avoid dropping them
Use php artisan make: commands (e.g., make:migration) to create new Laravel files; pass --no-interaction and appropriate options

Files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
database/migrations/**

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Keep database migrations under database/migrations

Files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
database/migrations/*.php

📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)

database/migrations/*.php: Place all Laravel database migrations under database/migrations and follow standard Schema::create/Schema::table structure
Always provide both up() and down() methods in migrations to ensure rollback support
Use incremental, reversible migrations; separate structural changes from data migrations when appropriate
Create appropriate indexes: primary keys, foreign key indexes, composite indexes for common queries, and unique constraints for business rules

Files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
app/Console/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)

Define Artisan console commands in app/Console

Files:

  • app/Console/Commands/CleanupRedis.php
  • app/Console/Commands/Dev.php
  • app/Console/Commands/Init.php
tests/Feature/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)

Place integration/request lifecycle tests under tests/Feature

tests/Feature/**/*.php: Feature tests (tests/Feature) may use database connections (migrations, models, factories)
Feature tests that touch the database must use the RefreshDatabase trait

Files:

  • tests/Feature/CoolifyTaskRetryTest.php
tests/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)

Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects

Add tests validating that components respect authorization (e.g., unauthorized users see disabled inputs; checkbox instantSave becomes false)

Include security tests covering SQL injection resistance, XSS validation, and enforcement of team isolation (403 on cross-team access).

Write tests using Pest (feature/unit) and include Laravel Dusk for browser scenarios as needed

Prefer Pest PHP as the primary testing framework for writing tests

Files:

  • tests/Feature/CoolifyTaskRetryTest.php
  • tests/Unit/ScheduledJobsRetryConfigTest.php
tests/**

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Keep automated tests (Pest/Dusk) under tests

Files:

  • tests/Feature/CoolifyTaskRetryTest.php
  • tests/Unit/ScheduledJobsRetryConfigTest.php
tests/{Feature,Unit}/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)

tests/{Feature,Unit}/**/*.php: All tests must be written using Pest and live under tests/Feature or tests/Unit
Use specific response assertion helpers (e.g., assertForbidden, assertNotFound) instead of generic assertStatus
Use datasets in Pest to reduce duplication where suitable (e.g., validation tests)
Write or update unit/feature tests for every change and run the affected tests

Files:

  • tests/Feature/CoolifyTaskRetryTest.php
  • tests/Unit/ScheduledJobsRetryConfigTest.php
resources/views/**/*.blade.php

📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)

Use semantic Tailwind CSS classes and consistent spacing in Blade templates

resources/views/**/*.blade.php: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)

resources/views/**/*.blade.php: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:canResource instead.
For custom interactive components not using x-forms.* (e.g., Alpine.js widgets), wrap with @can('gate', $resource) and provide a disabled/readonly fallback in @else with opacity-50 and cursor-not-allowed styling.

resources/views/**/*.blade.php: Prefer named routes and the route() helper when generating links in views
Dispatch events using $this->dispatch() (not emit/dispatchBrowserEvent) in Livewire 3 templates/components
Do not manually include Alpine.js; Livewire 3 bundles Alpine with required plugins

Files:

  • resources/views/livewire/project/shared/scheduled-task/show.blade.php
  • resources/views/livewire/project/shared/scheduled-task/add.blade.php
resources/**

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Store frontend assets and views under resources

Files:

  • resources/views/livewire/project/shared/scheduled-task/show.blade.php
  • resources/views/livewire/project/shared/scheduled-task/add.blade.php
resources/views/livewire/**/*.blade.php

📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)

Livewire components must have a single root element; use wire:key in loops and wire:loading/wire:dirty for UX

Files:

  • resources/views/livewire/project/shared/scheduled-task/show.blade.php
  • resources/views/livewire/project/shared/scheduled-task/add.blade.php
resources/**/*.{blade.php,vue}

📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)

Use Tailwind gap utilities for spacing lists instead of margins when listing items

Files:

  • resources/views/livewire/project/shared/scheduled-task/show.blade.php
  • resources/views/livewire/project/shared/scheduled-task/add.blade.php
app/Livewire/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)

Define Livewire components in app/Livewire and keep HTTP/UI concerns there

app/Livewire/**/*.php: Livewire components must authorize access in mount and before actions that mutate state
Expose only necessary public typed properties and register event listeners via the $listeners array in Livewire components

Place Livewire components under app/Livewire/ (e.g., Dashboard.php, ActivityMonitor.php, MonacoEditor.php)

Livewire 3 components should use the App\Livewire namespace and lifecycle hooks like mount() and updatedFoo()

Files:

  • app/Livewire/Project/Shared/ScheduledTask/Show.php
  • app/Livewire/Project/Shared/ScheduledTask/Add.php
app/Livewire/**

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Implement frontend components as Livewire classes under app/Livewire

Files:

  • app/Livewire/Project/Shared/ScheduledTask/Show.php
  • app/Livewire/Project/Shared/ScheduledTask/Add.php
{app/Http/Controllers/**/*.php,app/Livewire/**/*.php}

📄 CodeRabbit inference engine (.cursor/rules/README.mdc)

Authorize sensitive actions with policies (e.g., $this->authorize('deploy', $model)) before invoking services

Files:

  • app/Livewire/Project/Shared/ScheduledTask/Show.php
  • app/Livewire/Project/Shared/ScheduledTask/Add.php
tests/Unit/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)

Place unit tests under tests/Unit and keep them focused on individual classes/methods

tests/Unit/**/*.php: Unit tests (tests/Unit) must not use database connections or model factories
Unit tests must use mocking for models and external dependencies

Files:

  • tests/Unit/ScheduledJobsRetryConfigTest.php
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/application-architecture.mdc:0-0
Timestamp: 2025-08-27T14:59:11.004Z
Learning: Use Redis-backed queues with Horizon, batch jobs when appropriate, and implement retry handling for failed jobs
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to app/Jobs/**/*.php : Queue jobs should implement ShouldQueue and define retry strategy (tries, maxExceptions, backoff)
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to app/Models/**/*.php : Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models

Applied to files:

  • app/Models/ScheduledTaskExecution.php
  • app/Models/ScheduledTask.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to database/migrations/**/*.php : Create descriptive migrations with proper foreign keys, cascading deletes, indexes, and timestamps

Applied to files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
📚 Learning: 2025-10-15T09:14:50.127Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-10-15T09:14:50.127Z
Learning: Applies to database/migrations/*.php : Always provide both up() and down() methods in migrations to ensure rollback support

Applied to files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
📚 Learning: 2025-10-15T09:16:25.875Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-10-15T09:16:25.875Z
Learning: Applies to database/migrations/**/*.php : When modifying a column in a migration, re-specify all previously defined attributes to avoid dropping them

Applied to files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
📚 Learning: 2025-10-15T09:14:50.127Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-10-15T09:14:50.127Z
Learning: Applies to database/migrations/*.php : Use incremental, reversible migrations; separate structural changes from data migrations when appropriate

Applied to files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
📚 Learning: 2025-10-15T09:14:50.127Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-10-15T09:14:50.127Z
Learning: Applies to database/migrations/*.php : Place all Laravel database migrations under database/migrations and follow standard Schema::create/Schema::table structure

Applied to files:

  • database/migrations/2025_11_09_000001_add_timeout_to_scheduled_tasks_table.php
  • database/migrations/2025_11_09_000002_improve_scheduled_task_executions_tracking.php
📚 Learning: 2025-08-27T14:59:11.004Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/application-architecture.mdc:0-0
Timestamp: 2025-08-27T14:59:11.004Z
Learning: Use Redis-backed queues with Horizon, batch jobs when appropriate, and implement retry handling for failed jobs

Applied to files:

  • app/Console/Commands/CleanupRedis.php
  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • TESTING_GUIDE.md
📚 Learning: 2025-10-15T09:16:25.875Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-10-15T09:16:25.875Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Write or update unit/feature tests for every change and run the affected tests

Applied to files:

  • tests/Feature/CoolifyTaskRetryTest.php
📚 Learning: 2025-10-15T09:17:35.563Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/testing-patterns.mdc:0-0
Timestamp: 2025-10-15T09:17:35.563Z
Learning: Applies to tests/Feature/**/*.php : Feature tests (tests/Feature) may use database connections (migrations, models, factories)

Applied to files:

  • tests/Feature/CoolifyTaskRetryTest.php
📚 Learning: 2025-10-15T09:17:35.563Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/testing-patterns.mdc:0-0
Timestamp: 2025-10-15T09:17:35.563Z
Learning: Applies to tests/Feature/**/*.php : Feature tests that touch the database must use the RefreshDatabase trait

Applied to files:

  • tests/Feature/CoolifyTaskRetryTest.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to app/Jobs/**/*.php : Queue jobs should implement ShouldQueue and define retry strategy (tries, maxExceptions, backoff)

Applied to files:

  • tests/Feature/CoolifyTaskRetryTest.php
  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • tests/Unit/ScheduledJobsRetryConfigTest.php
  • TESTING_GUIDE.md
  • app/Jobs/DatabaseBackupJob.php
📚 Learning: 2025-10-15T09:13:00.453Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-10-15T09:13:00.453Z
Learning: Applies to app/Jobs/**/*.php : Queue jobs should update status, wrap external calls in try/catch, set failure status on exceptions, and rethrow

Applied to files:

  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • tests/Unit/ScheduledJobsRetryConfigTest.php
  • TESTING_GUIDE.md
  • app/Jobs/DatabaseBackupJob.php
📚 Learning: 2025-08-27T15:01:10.040Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/deployment-architecture.mdc:0-0
Timestamp: 2025-08-27T15:01:10.040Z
Learning: Applies to app/Jobs/*.php : Implement background deployment, monitoring, backup, and notification work as Laravel Job classes under app/Jobs

Applied to files:

  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • TESTING_GUIDE.md
  • app/Jobs/DatabaseBackupJob.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to app/Jobs/**/*.php : Queue jobs must handle success/failure state updates and broadcast corresponding events; implement failed(Throwable) for final failure handling

Applied to files:

  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/CoolifyTask.php
  • app/Jobs/DatabaseBackupJob.php
📚 Learning: 2025-10-15T09:16:25.875Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-10-15T09:16:25.875Z
Learning: Use queued jobs implementing ShouldQueue for time-consuming operations

Applied to files:

  • app/Jobs/ScheduledTaskJob.php
  • app/Jobs/DatabaseBackupJob.php
📚 Learning: 2025-08-27T14:59:11.004Z
Learnt from: CR
Repo: coollabsio/coolify PR: 0
File: .cursor/rules/application-architecture.mdc:0-0
Timestamp: 2025-08-27T14:59:11.004Z
Learning: Applies to app/Jobs/**/*.php : Queueable background work should be implemented as Jobs under app/Jobs; Actions may expose asJob to dispatch

Applied to files:

  • app/Jobs/CoolifyTask.php
  • app/Jobs/DatabaseBackupJob.php
🪛 LanguageTool
TESTING_GUIDE.md

[style] ~201-~201: This adverb was used twice in the sentence. Consider removing one of them or replacing them with a synonym.
Context: ...ted manually ✅ - [ ] CoolifyTask tested manually (server validation, container ops, or d...

(ADVERB_REPETITION_PREMIUM)

🔇 Additional comments (18)
templates/service-templates.json (1)

976-985: Verify scope alignment: Service template categorization vs. scheduled task improvements.

The PR description focuses on retry/timeout enhancements, error logging, and transient failure handling for scheduled tasks. However, this file updates service template categorization and tags to align with analytics classification. While the AI summary notes this as part of a "broader shift to analytics-driven categorization," the connection to scheduled task improvements is unclear.

Clarify whether these template changes are intentional for this PR or should be split into a separate issue.

Also applies to: 3667-3676

templates/service-templates-latest.json (2)

976-988: Verify alignment: service template changes vs. PR objectives on scheduled tasks.

The PR objectives emphasize enhanced retry logic, configurable timeouts, and improved error logging for scheduled tasks. However, this file contains only service template metadata updates (tag/category changes and Docker Compose configurations) with no apparent connection to scheduled task retry/timeout improvements. This suggests either the wrong file was provided for review, or the AI summary is misaligned with the actual PR scope.

Please clarify:

  1. How do these service template changes relate to the scheduled task retry/timeout enhancements described in the PR objectives?
  2. Are there other files in this PR that contain the actual scheduled task job logic (e.g., app/Jobs/CoolifyTask.php, ScheduledTaskJob.php, DatabaseBackupJob.php)?

3667-3667: Base64-encoded compose configuration cannot be visually reviewed.

Line 3667 replaces the "rybbit" compose field with a base64-encoded string that is too large to decode and verify in context. If this represents a significant update to the service configuration, consider:

  • Providing the decoded YAML in a separate supporting document for reviewability
  • Explicitly documenting what changed in the Compose spec (e.g., added services, new environment variables, updated health checks)
  • Ensuring the encoded content has been validated independently

Can you provide the decoded Docker Compose configuration for the rybbit entry so the changes can be properly reviewed for correctness, security, and alignment with retry/timeout features mentioned in the PR objectives?

Also applies to: 3676-3676

app/Models/ScheduledTask.php (1)

15-21: LGTM! Proper attribute casting.

The casts are correctly defined for the new timeout field and existing enabled field.

config/logging.php (1)

129-134: LGTM! Improved logging configuration for scheduled errors.

The changes appropriately increase log retention to 14 days and set the level to warning, which is suitable for monitoring task failures while reducing log verbosity.

app/Livewire/Project/Shared/ScheduledTask/Show.php (2)

43-44: LGTM! Well-defined timeout property.

The timeout property is properly validated with appropriate constraints (60-3600 seconds) and a sensible default of 300 seconds.


91-115: LGTM! Proper bidirectional data synchronization.

The syncData method correctly handles both directions:

  • When saving (toModel = true), it persists the timeout to the model
  • When loading (toModel = false), it initializes from the model with a fallback default
resources/views/livewire/project/shared/scheduled-task/add.blade.php (1)

7-9: LGTM! Clear and user-friendly timeout input.

The timeout field is well-positioned with helpful guidance text that explains the acceptable range and default value.

resources/views/livewire/project/shared/scheduled-task/show.blade.php (1)

38-39: LGTM! Consistent timeout input with edit form.

The timeout field is properly configured and consistent with the add form, providing a cohesive user experience.

tests/Feature/CoolifyTaskRetryTest.php (2)

10-40: LGTM! Well-structured dispatch test.

The test properly validates CoolifyTask dispatch with appropriate setup and assertions.


42-70: LGTM! Comprehensive retry configuration validation.

The test thoroughly validates all retry-related properties (tries, maxExceptions, timeout) and the backoff sequence, ensuring the job is configured correctly.

app/Livewire/Project/Shared/ScheduledTask/Add.php (4)

37-37: LGTM! Properly initialized timeout property.

The timeout property is correctly typed and initialized with a sensible default value.


39-53: LGTM! Comprehensive validation rules.

The validation rules and attributes for timeout are properly defined and consistent with the Show component.


102-130: LGTM! Proper task persistence.

The timeout is correctly assigned when saving the scheduled task.


132-139: LGTM! Proper form reset.

The clear method correctly resets the timeout to its default value.

tests/Unit/ScheduledJobsRetryConfigTest.php (3)

7-22: LGTM! Thorough CoolifyTask configuration validation.

The test uses reflection to verify both the presence and default values of retry-related properties and methods.


24-40: LGTM! ScheduledTaskJob retry validation.

The test properly validates retry configuration including the timeout property specific to ScheduledTaskJob (300 seconds, matching the UI default).


42-56: LGTM! DatabaseBackupJob configuration check.

The test correctly validates DatabaseBackupJob's retry properties with appropriate default values (tries=2, maxExceptions=1).

@andrasbacsai andrasbacsai merged commit 3def8ce into next Nov 11, 2025
5 checks passed
@andrasbacsai andrasbacsai deleted the improve-scheduled-tasks branch November 11, 2025 11:36
@andrasbacsai andrasbacsai mentioned this pull request Nov 11, 2025
@arthur-fontaine
Copy link

Hi @andrasbacsai, we use Coolify and scheduled tasks at work.
Is there any technical reason why the maximum timeout is limited to 3600 seconds?
Also, is there a way to disable the retry policy?

@andrasbacsai andrasbacsai mentioned this pull request Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants