Laravel Queue Job Running Immediately - laravel

I have a laravel queue setup to a database. When I run dd(env('QUEUE_DRIVER')) I get database back. When I create a job it is run right away. I would like the job to be queued until I run php artisan queue:work. What do I need to do to have the job not run right away. Thanks!
Edit 1:
Dispatch Code:
for ($i=0; $i < 100; $i++) {
$job = new UpdateJob("");
dispatch($job);
}
Job Code:
public function handle(){
sleep(30);
SlackApi::SendMessage("Job!");
}
When I run this I get a slack message every 30 seconds. But none of these jobs are being stored in the DB.
Edit 2:
Even when I add ->delay(Carbon::now()->addMinutes(10)) to the job the job is still run right away.

The issue seems to come from upgrading from v5.1 to v5.4 I added Illuminate\Bus\BusServiceProvider::class to my providers in app.php and that fixed everything.

Is any supervisor running? if the supervisor is configure the queue will be take care of the job as son as it's added to the queue. if you want a delayed dispatch of the job you must specify the delay. Take a look into https://laravel.com/docs/5.4/queues#delayed-dispatching for more details

Related

Beanstalkd Queue either fails or runs infinitely

I am using a Beanstalkd queue to deploy jobs in my Laravel 5.3 application. I use Laravel Forge to administer the server.
I have one of two scenarios that occur:
1) I set a max number of attempts, which causes every job pushed to the queue to be placed on the failed jobs table - even if its task is completed successfully, resulting in this exception on the jobs table:
Illuminate\Queue\MaxAttemptsExceededException: A queued job has been attempted too many times. The job may have previously timed out
And this in my error log:
Pheanstalk\Exception\ServerException: Server reported NOT_FOUND
2) If I remove the max attempts, the jobs run successfully but in an infinite loop.
I am assuming that I am not removing these jobs from the queue properly and so in scenario #1 the job is failing because just wants to keep running.
My controller pushes my job to the queue like this:
Queue::push('App\Jobs\UpdateOutlookContact#handle', ['userId' => $cs->user_id, 'memberId' => $member->id, 'connection' => $connection]);
Here is the handle function of my job:
public function handle($job, $data)
{
Log::info('Outlook syncMember Job dispatched');
$outlook = new Outlook();
$outlook->syncMember($data['userId'], $data['memberId'], $data['connection']);
$job->delete();
}
Here is a picture of my queue configuration from the Laravel Forge admin panel. I am currently using the default queue. If "Tries" is changed to ANY, the jobs succeed but run in an infinite loop.
How do I properly remove these jobs from the queue?

Laravel 5 / L5: Set number of attempts when pushing job to a queue using Database connection

I have setup the Queue system in L5 using the Databse connection and after i run the migration I have two tables in my DB failed_jobs and jobs. Everything is working fine so far but when the pushed operation failed its keep going and trying to process the operation and did not delete the job on fail or inserted on failed_jobs
Queue::push(function($job) use ($id)
{
Account::delete($id);
$job->delete();
});
In the above example how can I set number of attempts to try if not success and then insert into failed_jobs.
I know this can be done using
php artisan queue:listen --tries=3
But I want the same using the Closures as I have different cases
You can check the number of attempts:
if ($job->attempts() > 3)
{
//
}
This is clearly mentioned in the documentation here.
You can define the maximum number of attempts on the job class itself.
If the maximum number of attempts is specified on the job, it will take precedence over the value provided on the command line.
Add this to your job class:
/**
* The number of times the job may be attempted.
*
* #var int
*/
public $tries = 5;

Laravel liebig/cron executes the cronjob twice for same time

I am using laravel 4.2.
I've a project requirement to send some analysis report email to all the users every Monday 6 am.
Obviously its a scheduled task, hence I've decided to use cron-job.
For this I've installed liebig/cron package. The package is installed successfully. To test email, I've added following code in app/start/global.php:
Event::listen('cron.collectJobs', function() {
Cron::setEnablePreventOverlapping();
// to test the email, I am setting the day of week to today i.e. Tuesday
Cron::add('send analytical data', '* * * * 2', function() {
$maildata = array('email' => 'somedomain#some.com');
Mail::send('emails.analytics', $maildata, function($message){
$message->to('some_email#gmail.com', 'name of user')->subject('somedomain.com analytic report');
});
return null;
}, true);
Cron::run();
});
Also in app\config\packages\liebig\cron\config.php the key preventOverlapping is set to true.
Now, if I run it like php artisan cron:run, it sends the same email twice with the same time.
I've deployed the same code on my DigitalOcean development server (ubuntu) and set its crontab to execute this command every minute but still it is sending the same email twice.
Also it is not generating lock file in app/storage directory, according to some search results I've come to know that it creates a lock file to prevent overlapping. the directory has full permissions granted.
Can anybody knows how to solve it?
Remove Cron::run().
Here's what's happening:
Your Cron route or cron:run command is invoked.
Cron fires off the cron.collectjobs event to get a list of events.
You call Cron::run() and run all the events.
Cron calls Cron::run() and runs all the events.
In the cron.collectjobs event you should only be making a list of jobs using Cron::add().
The reason you're not seeing a lock file is either that preventOverlapping is set to false (it's true by default), or that the jobs are running so fast you don't see it being created and deleted. The lock file only exists for the time the jobs run, which may only be milliseconds.

Circular queue on beanstalkd

I'm using beanstalkc a python wrapper for the beanstalkd application.
What I'd like to do is have the producer to put some jobs(e.g: 'a','b','c','d') once and that the consumer could get the jobs continually(e.g: 'a','b','c','d','a','b',...).
In the consumer I get the jobs with job.reserve(). I thought the solution was just reserving the jobs without deleting them, but after I ran some consumer processes I got a TIMEOUT ERROR.
I'm clearly doing something wrong but I couldn't find a way to "re-queue" the jobs the consumers use.
I think this could be a solution:
producer:
queue.put('a', priority=0)
Consumer:
job = queue.reserve()
do something with job
new_priority = job.stats()['pri'] + 1
job.release(priority=new_priority)
Why not just, when you've completed a particular job, and after you've released it, put another copy of the same job you've just finished back into the queue?
You'd otherwise be trying to get it to do something that it's not designed to do.

Run #Scheduled task only on one WebLogic cluster node?

We are running a Spring 3.0.x web application (.war) with a nightly #Scheduled job in a clustered WebLogic 10.3.4 environment. However, as the application is deployed to each node (using the deployment wizard in the AdminServer's web console), the job is started on each node every night thus running multiple times concurrently.
How can we prevent this from happening?
I know that libraries like Quartz allow coordinating jobs inside clustered environment by means of a database lock table or I could even implement something like this myself. But since this seems to be a fairly common scenario I wonder if Spring does not already come with an option how to easily circumvent this problem without having to add new libraries to my project or putting in manual workarounds.
We are not able to upgrade to Spring 3.1 with configuration profiles, as mentioned here
Please let me know if there are any open questions. I also asked this question on the Spring Community forums. Thanks a lot for your help.
We only have one task that send a daily summary email. To avoid extra dependencies, we simply check whether the hostname of each node corresponds with a configured system property.
private boolean isTriggerNode() {
String triggerHostmame = System.getProperty("trigger.hostname");;
String hostName = InetAddress.getLocalHost().getHostName();
return hostName.equals(triggerHostmame);
}
public void execute() {
if (isTriggerNode()) {
//send email
}
}
We are implementing our own synchronization logic using a shared lock table inside the application database. This allows all cluster nodes to check if a job is already running before actually starting it itself.
Be careful, since in the solution of implementing your own synchronization logic using a shared lock table, you always have the concurrency issue where the two cluster nodes are reading/writing from the table at the same time.
Best is to perform the following steps in one db transaction:
- read the value in the shared lock table
- if no other node is having the lock, take the lock
- update the table indicating you take the lock
I solved this problem by making one of the box as master.
basically set an environment variable on one of the box like master=true.
and read it in your java code through system.getenv("master").
if its present and its true then run your code.
basic snippet
#schedule()
void process(){
boolean master=Boolean.parseBoolean(system.getenv("master"));
if(master)
{
//your logic
}
}
you can try using TimerManager (Job Scheduler in a clustered environment) from WebLogic as TaskScheduler implementation (TimerManagerTaskScheduler). It should work in a clustered environment.
Andrea
I've recently implemented a simple annotation library, dlock, to execute a scheduled task only once over multiple nodes. You can simply do something like below.
#Scheduled(cron = "59 59 8 * * *" /* Every day at 8:59:59am */)
#TryLock(name = "emailLock", owner = NODE_NAME, lockFor = TEN_MINUTE)
public void sendEmails() {
List<Email> emails = emailDAO.getEmails();
emails.forEach(email -> sendEmail(email));
}
See my blog post about using it.
You don't neeed to synchronize your job start using a DB.
On a weblogic application you can get the instanze name where the application is running:
String serverName = System.getProperty("weblogic.Name");
Simply put a condition two execute the job:
if (serverName.equals(".....")) {
execute my job;
}
If you want to bounce your job from one machine to the other, you can get the current day in the year, and if it is odd you execute on a machine, if it is even you execute the job on the other one.
This way you load a different machine every day.
We can make other machines on cluster not run the batch job by using the following cron string. It will not run till 2099.
0 0 0 1 1 ? 2099

Resources