Skip to content

add fleet missions queue #363 feature#817

Open
yazilimmz wants to merge 9 commits into
lanedirt:mainfrom
yazilimmz:363-queue-missions
Open

add fleet missions queue #363 feature#817
yazilimmz wants to merge 9 commits into
lanedirt:mainfrom
yazilimmz:363-queue-missions

Conversation

@yazilimmz

Copy link
Copy Markdown
Contributor

Description

Please include a summary of the changes made to OGameX and their purpose. Clearly describe what this PR does and why it is necessary.

Type of Change:

  • Bug fix
  • Feature enhancement
  • Documentation update
  • Other (please describe):

Related Issues

Fixes #363

Checklist

Before submitting this pull request, ensure all following requirements as outlined in CONTRIBUTING.md are met:

  • Code Standards: Code adheres to PSR-12 coding standards. Verified with Laravel Pint.
  • Static Analysis: Code passes PHPStan static code analysis.
  • Testing:
    • Relevant unit and feature tests are included or updated.
    • Tests successfully run locally.
  • CSS & JS Build: CSS and JS assets are compiled using Laravel Mix if any changes are made to JS/CSS files.
  • Documentation: Documentation has been updated to reflect any changes made.

Additional Information

  • Aim for near real-time processing: missions should be executed within 1-3 seconds of their scheduled time.

  • Ensure scalability to handle multiple concurrent missions across the game universe. E.g. missions for different planets that do not conflict with each other can be processed concurrently and do not necessarily have to wait for each other.

  • Implement logging and error handling for mission processing.

  • Consider edge cases like server downtime or processing delays.

Additionally, testing was becoming too difficult. I added a command for this. You can run it like: php artisan fleet:test-queue 5 1 347 12 --delay=5. This command will launch 3 simultaneous attacks to the coordinates you specify. You can also reduce this in terms of duration by increasing the battle speed from settings. You can remove this optionally.

@yazilimmz

yazilimmz commented Nov 22, 2025

Copy link
Copy Markdown
Contributor Author

I’m not fixing the error in the phalanx test because it has already been resolved in this commit. It will be fixed once we merge. thx @Geda173
ab8cc33

@lanedirt

Copy link
Copy Markdown
Owner

Hi @yazilimmz, thanks a lot for your work on making the fleet mission processing more robust!

The ab8cc33 commit has just been merged and I have re-ran the tests.

The custom php artisan race condition tests now however seem to fail. They probably need to be refactored a bit to account for the new system?

I'll try and functionally test the changes once all actions succesfully run.

@jackbayliss jackbayliss left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I've added some minor questions / feedback while on my travels 🫡

Comment thread app/GameMissions/Abstracts/GameMission.php Outdated
Comment thread app/Jobs/ProcessFleetMissions.php Outdated
// Update all fleet missions of player that are associated with any of the player's planets.
$player->updateFleetMissions();

if (app()->environment('testing')) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How come we're only doing this during testing? Would we not expect this in prod?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We don't expect this in the production environment, because in production it runs through Laravel's queue system

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Is it possible to refactor the feature tests so they do use the Laravel's queue system, so we can assert that the queue processing etc. works using the existing test suite?

I'm not very familiar with Laravel's queue system, but as the feature tests hit the actual database, the queue system should also be able to work normally, right?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It's possible to run assertions using Queue::fake();

So I'd expect to that that IMO.

👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We use travelTo to simulate fleet events. Unfortunately, with Redis queue, we cannot trigger a battle or a fleet event using travelTo. With $player->updateFleetMissions();, we are already testing the function inside the queue anyway.

@lanedirt lanedirt left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Hi @yazilimmz, I have tested the change locally, and functionally it seems to work great.

However one main thing I do notice is that mission processing now feels a bit sluggish, in the sense that after a mission has arrived, it takes 1-2 seconds before the mission is actually processed.

During this time the mission is not processed, it stays visible in the fleet mission event bar as "Finished". Even when you reload the page it can look like this for 1-2 seconds:

Image

Due to this new delay, it might make sense that we do not show missions in the "Fleet movement" bar if the time_arrival in the past. I think the official OGame does this too. But we can do this in a follow up PR too.

One central question though: is there any possibility in making the queue system more responsive? E.g. even shaving off 0.5 seconds in the response time can make the game feel more snappy.

Comment thread .env.example
Comment on lines +31 to 33
REDIS_HOST=ogamex-redis
REDIS_PASSWORD=null
REDIS_PORT=6379

@lanedirt lanedirt Nov 25, 2025

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This change here means all existing deployments who want to upgrade also need to change their .env, correct?

I tested this PR locally without making this .env change, but as the docker-compose.yml (dev) does expose a port it works via the old 127.0.0.1 connection. But on production deployments this won't work.

I'm thinking we may want to add some sort of initialize script somewhere during docker container start to check for and update default .env values. Such an initialization script does not exist yet, but it would be helpful for future (default) changes too. Because right now without instructions, if someone follows the current upgrade instructions in the README.md, the fleet queue will break.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Using a script could overwrite the user's custom values. I think updating the README.md would be a better approach. Something like:
"If you are upgrading from version 0.13.0 or earlier, please add REDIS_HOST=ogamex-redis to your .env file."

@yazilimmz

Copy link
Copy Markdown
Contributor Author

One central question though: is there any possibility in making the queue system more responsive? E.g. even shaving off 0.5 seconds in the response time can make the game feel more snappy.

Good catch! I've reduced the queue worker sleep time from the default 3 seconds to 0.5 seconds. This should make the queue much more responsive.
php artisan queue:work redis --sleep=0.5
Laravel's queue worker already supports sub-second sleep values using usleep() internally, so no custom implementation was needed.
If you still experience delays, we can also try the block_for option in config/queue.php which uses Redis's native BLPOP for even more instant response times.

@yazilimmz

Copy link
Copy Markdown
Contributor Author

@lanedirt Is there anything you expect from me for this PR?

@lanedirt

Copy link
Copy Markdown
Owner

@lanedirt Is there anything you expect from me for this PR?

Looks good so far, thank you! I just haven’t had the time to properly test it again, and also deciding about best way to go for the upgrade notice or script. I’ll review it soon and get back to you.

@lanedirt

lanedirt commented Nov 28, 2025

Copy link
Copy Markdown
Owner

I have just tested it again on my local environment. I have two areas that could use some further thought:

Redis persistence

Right now, Redis is by default configured with appendfsync everysec, which means there's a ~1 second window where data can be lost if Redis crashes right after a job is dispatched.

The scenario:

  1. Fleet mission created → saved to MariaDB (processed=0)
  2. Job dispatched to Redis with ->delay($arrival_time)
  3. Redis crashes or is restarted within 1 second, before fsync → job lost
  4. MySQL still has processed=0 → mission never executes

To combat this, I think setting the appendfsync option explicitly to always would be a better default which makes Redis write to disk on every transaction, even though it can incur a (small) performance penalty.

Resumability

Two scenarios will cause fleet missions to never be processed:

  • Updating existing OGameX server: When updating to this PR, the Redis queue starts empty. Any in-flight missions (already scheduled but not yet arrived) won't have Redis jobs - they'll be stuck in MariaDB with processed=0 forever.
  • Redis unavailable during dispatch: If Redis is down/unreachable when ProcessFleetMissions::dispatch() is called, the FleetMission record is saved to MariaDB but no job is queued. Mission never processes.

The FIFO check makes this worse: The current code waits for earlier unprocessed missions before processing later ones. So if mission A (arrival 10:00) has no Redis job, mission B (arrival 10:15) will keep releasing itself every second waiting for A, which will never come. I'm seeing this locally now actually: I have 295 orphaned missions (from lots of earlier tests) causing some of my new manual dispatched missions to stall indefinitely in a release(1) loop. E.g. this is what my ogamex-queue-worker log looks like right now, its trying to re-process the same job every second but gets stuck due to the FIFO check:

ogamex-queue-worker  |   2025-11-28 20:08:38 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  61.20ms DONE
ogamex-queue-worker  |   2025-11-28 20:08:39 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  RUNNING
ogamex-queue-worker  |   2025-11-28 20:08:39 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  58.62ms DONE
ogamex-queue-worker  |   2025-11-28 20:08:40 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  RUNNING
ogamex-queue-worker  |   2025-11-28 20:08:40 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  56.07ms DONE
ogamex-queue-worker  |   2025-11-28 20:08:41 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  RUNNING
ogamex-queue-worker  |   2025-11-28 20:08:41 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  55.52ms DONE
ogamex-queue-worker  |   2025-11-28 20:08:42 OGame\Jobs\ProcessFleetMissions 51EsdUljwdWOI3oxMRtcJ72fEQLRjtCO redis default  RUNNING

laravel.log:

[2025-11-28 20:27:57] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:27:58] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:27:58] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:27:58] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:27:59] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:27:59] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:27:59] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:28:00] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:28:00] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:28:00] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:28:01] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:28:01] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:28:01] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:28:02] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:28:02] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:28:02] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:28:03] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:28:03] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:28:03] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:28:04] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:28:04] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:28:04] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 
[2025-11-28 20:28:05] local.INFO: FLEET MISSION STARTED FOR PLANET 629  
[2025-11-28 20:28:05] local.INFO: FLEET OLDER MISSION EXISTS {"exists":true} 
[2025-11-28 20:28:05] local.INFO: FLEET MISSION WAITING {"mission_id":115286,"planet_id_to":629,"time_arrival":1764360500,"reason":"Earlier-arriving mission exists, maintaining FIFO order by arrival time"} 

So for this I think we'll need some kind of resume functionality, where it periodically checks for jobs that have arrived (time_arrival in past) but have not been processed yet. These jobs should be re-added to the Redis queue (if they are not already being processed or in the queue, which is a possibility for potential long running battles).

Can you look into this? If I made a wrong observation or assumption, feel free to correct me. Thanks again for your work on this!

@yazilimmz

Copy link
Copy Markdown
Contributor Author

Thanks a lot for the detailed analysis. your observations make sense.

Redis persistence:
You're right about the appendfsync window. Switching to appendfsync always seems like a safer option to avoid losing delayed jobs

Resumability:
We’ll need a mechanism to recover missions whose arrival time has passed but were never queued.
A possible approach is a command that runs every 30 seconds and re-queues missions with time_arrival < now and processed = 0

Return-phase missions & long battle times
Since some battle reports can take minutes to proces, we should avoid re-queueing missions that already finished their outbound processing and are returning
To prevent duplicating return jobs we can add a third field to the fleet_missions table (e.g. processing_stage or executed) so the resumability scan does not requeue already-executed-but-returning missions

FIFO:
Real FIFO ordering is only guaranteed when using Amazon SQS FIFO queues as Laravel documents here:
https://laravel.com/docs/12.x/queues#sqs-fifo-and-fair-queues

Since Redis cannot guarantee strict FIFO modifying the FIFO logic deeply may cause more issues (like endless release loops).
So instead of forcing FIFO at the queue level improving resumability seems like the safer path

Geda173 pushed a commit to Geda173/OGameX that referenced this pull request Dec 28, 2025
Addresses issue lanedirt#363 by documenting a comprehensive plan for implementing
a Redis-backed queue system that ensures fleet missions are processed in
strict chronological order by arrival time.

Key components:
- Redis container and PHP extension setup
- ProcessFleetMission job with FIFO ordering
- Orphan mission recovery mechanism
- Dual-mode operation for test compatibility
- Migration path for existing deployments

Based on analysis of current codebase and PR lanedirt#817 discussion.
@lanedirt lanedirt added the help wanted Extra attention is needed label Jan 21, 2026
@tiweb442

Copy link
Copy Markdown
Contributor

Status note / handoff

This PR pioneered the Redis delayed-job approach for #363, but the remaining blockers from the Nov 28 review (Redis appendfsync, orphan resumability, FIFO release(1) loops, REDIS_HOST upgrade path) are still open and the branch is now merge-conflicting with main.

Suggested path forward: #1413 is a more complete take on the same issue that already solves those blockers (database queue + scheduler catch-up + destination locks + tests). A small hardening follow-up for timeout/sleep is in Geda173/OGameX#68.

Unless there is a strong reason to keep the Redis-based design, closing this in favor of #1413 (and crediting the groundwork here) would probably reduce confusion for new contributors.

@tiweb442

Copy link
Copy Markdown
Contributor

Update: #1413 has been rebased onto current main and smoke-tested — see #1508 (and the note on #1413). That path remains the recommended one for #363 vs continuing this Redis-based PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

help wanted Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement worker queue / cron system to chronologically process fleet missions

4 participants