Three application servers each running the same crontab means every scheduled task runs three times, and the invoice job discovers this before you do.
$schedule->command('invoices:generate')
->dailyAt('02:00')
->onOneServer()
->withoutOverlapping();
// requires a shared cache driver — redis or memcached.
// the file driver is per-machine, which defeats the purpose silently.
The lock is a cache key with a short expiry, claimed by whichever server reaches it first. The requirement that the cache be shared is stated in one line of the documentation and is the thing that goes wrong: a stack using the file driver gets no error and no protection. withoutOverlapping() solves a different problem — a run that takes longer than its interval — and the two are frequently both wanted.