<p>With the recent release of <a href="http://buildwithcraft.com/updates#build2632" rel="nofollow">2.3.2632</a>, I've had success with curling the runPendingTask action as an ajax request.</p>

<pre><code>0 2 * * * curl -H "X-Requested-With: XMLHttpRequest" http://example.com/actions/myPlugin/someController/runSomeTask
9 2 * * * curl -H "X-Requested-With: XMLHttpRequest" http://example.com/actions/tasks/runPendingTasks
</code></pre>

<p>So queue up the tasks, then 9 minutes later, run them.</p>

<p>The tasks controller will gracefully run the pending tasks. And since the request is an AJAX one, the controller will close the connection so you won't have any open HTTP requests while all of the tasks finish.</p>

CC BY-SA 3.0
2015-11-19T10:29:26.170Z
I think I'm going to use this tactic. Any ideas on how to make this run-able by the server only... i.e. no direct access via url?
H2ONOCK
CC BY-SA 3.0
2017-06-05T15:32:45.127Z
Does this mean that accessing the plugin directly doesn't actually run it, it is just added to the task queue? And will not fully excute until CP is accessed, unless you run the pending tasks manually?

I'm trying to run a plugin that updates externally loaded data from a cronjob (I used wget, not curl), and it seems not to work reliably. The problem may be elsewhere, but it works totally fine when running it manually from the CP at least.
KSP
CC BY-SA 3.0
2015-04-09T18:47:21.407Z
2015-04-09T18:47:21.407Z
Janson Hartliep
<p>Ok, you are probably nearly there - all you need to do is call that controller action from the outside world. Here is a small example:</p>

<pre><code>&lt;?php
namespace Craft;

class MyPlugin_SomeController extends BaseController
{

  // this lets anyone run the controller actions we specify
  protected $allowAnonymous = = array('actionRunSomeTask');

  // this is the controller function you want to call
  public function actionRunSomeTask()
  {
    craft()-&gt;tasks-&gt;createTask('MyPlugin_Task');
    echo 'Task started!';
    craft()-&gt;end();
  }
}
</code></pre>

<p>Then you can access the url <a href="http://example.com/actions/myPlugin/someController/runSomeTask" rel="nofollow">http://example.com/actions/myPlugin/someController/runSomeTask</a> however you like. In cron you could then use something like <code>wget</code> to get the url:</p>

<pre><code>0 2 * * * wget http://example.com/actions/myPlugin/someController/runSomeTask
</code></pre>

<p>All this information and more can be found in the docs: <a href="http://buildwithcraft.com/docs/plugins/controllers" rel="nofollow">http://buildwithcraft.com/docs/plugins/controllers</a>.</p>

<p><strong>Edit:</strong></p>

<p>I didn't really grasp the issue which is that Tasks only get set off when the cp is requested. To that end, one solution is to use something like PhantomJS to log in to the cp purely to start off the tasks. I have done this to actually set going something else more complex but here is a cleaned up example using PhantomJS and CasperJS to just access the cp and log in:</p>

<pre><code>// make casper
var casper = require('casper').create();

// log in
casper.start('http://example.com/admin/login', function(){
  this.fill('#login-form', {
    'username' : 'someuser',
    'password' : 'somepassword'
  }, true);
});

// wait for the dashboard
casper.waitForUrl(http://example.com/admin/dashboard', function(){
  this.echo('Yay, logged in!');

  // maybe check for some evidence of the task running here

  casper.exit();
});

// tell casper to run the above sequence
casper.run();
</code></pre>

<p>I'm pretty sure at some point P&amp;T will sort something more native out but for now this would work.</p>

CC BY-SA 3.0
2014-07-24T08:40:01.050Z
Hi, thanks for the reply. I actually had the controller setup pretty much the same as you have shown. The only difference is that the task gets created from within the sendNotificationsEmail() function which is in the plugins service. I stripped things back to be like in your example but it seems that tasks only get processed the next time the CP is visited. Is there something I'm missing?
Dave Coggins
CC BY-SA 3.0
2014-07-24T08:45:47.333Z
Ah, yes sorry - that is totally true. I just found where Brandon mentioned it on gplus: "you have to access the CP to trigger them in the first place (and even that is probably not going to be necessary down the road when I have a chance to test out an idea I have)" - see the comments here: https://plus.google.com/+LukeHolder/posts/Tc8w1Lr7Czw.

I'm not sure there is a way at present to ping the tasks save for logging into the cp. I have done this with PhantomJS though...
Josh Angell
CC BY-SA 3.0
2014-07-24T13:33:47.293Z
Thanks for the code for casperjs, never come across it before, I can see it being useful in the future. I did get it working as you suggested but then saw the answer from Mike which seem the more crafty way of doing things. Thanks for taking the time to respond to the question. I'm only 3 days into developing with Craft and I'm amazed by what can be achieved and the support of the community. I hope to be able to pitch in soon once I've got the hangs of things :)
Dave Coggins
CC BY-SA 3.0
2014-07-24T13:43:15.840Z
Yeah, I completely failed to actually look at the TaskService since I first had a dig months back, which was silly really as P&T clearly have introduced those things they said they would! Best of luck with it all :)
Josh Angell
CC BY-SA 3.0
2015-08-15T02:43:10.690Z
Hi Josh? Any chance you d share more of the plugin using this casper js integration ? I am very interested by that but I am too much of a plugin dev dummy to make it.
migmaker
CC BY-SA 3.0
2015-08-15T06:58:38.467Z
Hey @migswd we've actually moved away from using CasperJS and are fully invested in Tasks now for this sort of things. But if you'd still like to see what we did I'm more than happy to share. Just drop me an email and I'll send you something on Monday - josh@supercooldesign.co.uk
Josh Angell
CC BY-SA 3.0
2014-07-24T07:41:00.057Z
2014-07-24T09:11:35.737Z
2014-07-24T09:11:35.737Z
Josh Angell
<p>You may also want to register your route in your YourPlugin.php file, using the registerSiteRoutes method, example below:</p>

<pre><code>public function registerSiteRoutes()
{
    return array(
        'myroute' =&gt; array('action' =&gt; 'myPlugin/myAction')
    );
}
</code></pre>

CC BY-SA 3.0
2017-04-25T13:56:29.693Z
2017-04-25T13:56:29.693Z
Brad
<p>I made a free plugin that may help. I had trouble running through http when there were many tasks.</p>

<p>The plugin executes tasks purely as cron (i.e. does not internally issue a curl or wget request).</p>

<p>I made the plugin available at:
<a href="https://straightupcraft.com/craft-plugins/taskrunner" rel="nofollow noreferrer">https://straightupcraft.com/craft-plugins/taskrunner</a></p>

<p>or you can view the code at:
<a href="https://gitlab.com/24hoursmedia/craft2-plugins/craft2-taskrunner" rel="nofollow noreferrer">https://gitlab.com/24hoursmedia/craft2-plugins/craft2-taskrunner</a></p>

CC BY-SA 3.0
2017-06-17T16:17:08.843Z
2017-06-17T16:17:08.843Z
24HOURSMEDIA
<p>Everything you need to manage tasks is in the <strong>TasksService</strong>, so you should be able to just use that in your controller action to kick off any pending tasks, using something along the lines of:</p>

<pre><code>if (!craft()-&gt;tasks-&gt;isTaskRunning())
{
    $task = craft()-&gt;tasks-&gt;getNextPendingTask();

    if ($task)
    {
        craft()-&gt;tasks-&gt;runPendingTasks();
    }
}
</code></pre>

<p>If you have a look around <strong>craft/app/services/TasksService.php</strong> you'll see you can also grab and run tasks by type which might be useful in this situation.</p>

CC BY-SA 3.0
2014-07-24T11:19:40.383Z
Wish I'd just looked the TasksService now...
Josh Angell
CC BY-SA 3.0
2014-07-24T09:42:17.650Z
2014-07-24T09:42:17.650Z
Mike Pepper
<p>I have a site setup which is for subscribers only. I have added a user expiry date field to the users section and everything is working perfectly on the front end in that I can restrict access to accounts that have already passed their expiry date. </p>

<p>However I need to send notification emails to accounts that expire today or will expire in 7 days time.</p>

<p>I am using the mailer plugin in combination with a basic plugin I have made. I have setup a basic plugin with a controller which calls the following function from the plugins service:</p>

<pre><code>public function sendNotificationEmail()
{
    //Create an EmailModel
    $email = new EmailModel;

    //Set the necessary attributes 
    $email-&gt;fromName = 'Joe Blogs';
    $email-&gt;fromEmail = 'joe.blogs@example.com';
    $email-&gt;subject     = 'Email subject';
    $email-&gt;htmlBody    = 'The message';


    //RecipientsModel
    $recipients = new Mailer_RecipientsModel();
    $recipients-&gt;recipients = array(
        array(
            'to' =&gt; 'jane.doe@example.com'
        )
    );

    if( $recipients-&gt;validate()){
        //Create mailer
        craft()-&gt;mailer_main-&gt;newMailer($recipients, $email); //This will start the MailerTask
    }


}
</code></pre>

<p>As you can see, at the moment I'm just sending a single test email each time. Everything works as expected but I've noticed that the task does not get triggered until I refresh the CP. This is a problem in my case, I think, because I want to trigger everything from a CRON job.</p>

<p>If anyone has any solution as to how to automatically trigger the task or if there are any alternative methods to solve this problem, I'd love to here them :)</p>

<p>btw, the reason I went down the task route was that the system could be sending to 100s of email addresses at a time and I didn't want to be (a) treated as spam or (b) get a timeout from the request</p>

<plugins><tasks>
Triggering the start of a task from a CRON job
# Triggering the start of a task from a CRON job

(Asked by: username_0 on 2014-07-24)

I have a site setup which is for subscribers only. I have added a user expiry date field to the users section and everything is working perfectly on the front end in that I can restrict access to accounts that have already passed their expiry date. 
However I need to send notification emails to accounts that expire today or will expire in 7 days time.
I am using the mailer plugin in combination with a basic plugin I have made. I have setup a basic plugin with a controller which calls the following function from the plugins service:
public function sendNotificationEmail()
{
    //Create an EmailModel
    $email = new EmailModel;

    //Set the necessary attributes 
    $email->fromName = 'Joe Blogs';
    $email->fromEmail = 'joe.blogs@example.com';
    $email->subject     = 'Email subject';
    $email->htmlBody    = 'The message';


    //RecipientsModel
    $recipients = new Mailer_RecipientsModel();
    $recipients->recipients = array(
        array(
            'to' => 'jane.doe@example.com'
        )
    );

    if( $recipients->validate()){
        //Create mailer
        craft()->mailer_main->newMailer($recipients, $email); //This will start the MailerTask
    }


}

As you can see, at the moment I'm just sending a single test email each time. Everything works as expected but I've noticed that the task does not get triggered until I refresh the CP. This is a problem in my case, I think, because I want to trigger everything from a CRON job.
If anyone has any solution as to how to automatically trigger the task or if there are any alternative methods to solve this problem, I'd love to here them :)
btw, the reason I went down the task route was that the system could be sending to 100s of email addresses at a time and I didn't want to be (a) treated as spam or (b) get a timeout from the request

**Tags:** plugins, tasks

---

## 5 answers

### Answer by username_8 on 2014-07-24. Score: 10 | Accepted answer

Everything you need to manage tasks is in the TasksService, so you should be able to just use that in your controller action to kick off any pending tasks, using something along the lines of:
if (!craft()->tasks->isTaskRunning())
{
    $task = craft()->tasks->getNextPendingTask();

    if ($task)
    {
        craft()->tasks->runPendingTasks();
    }
}

If you have a look around craft/app/services/TasksService.php you'll see you can also grab and run tasks by type which might be useful in this situation.

> **Comments:**
> **username_4**: Wish I'd just looked the TasksService now...  

---

### Answer by username_1 on 2015-04-09. Score: 4

With the recent release of 2.3.2632, I've had success with curling the runPendingTask action as an ajax request.
0 2 * * * curl -H "X-Requested-With: XMLHttpRequest" http://example.com/actions/myPlugin/someController/runSomeTask
9 2 * * * curl -H "X-Requested-With: XMLHttpRequest" http://example.com/actions/tasks/runPendingTasks

So queue up the tasks, then 9 minutes later, run them.
The tasks controller will gracefully run the pending tasks. And since the request is an AJAX one, the controller will close the connection so you won't have any open HTTP requests while all of the tasks finish.

> **Comments:**
> **username_2**: I think I'm going to use this tactic. Any ideas on how to make this run-able by the server only... i.e. no direct access via url?  
> **username_3**: Does this mean that accessing the plugin directly doesn't actually run it, it is just added to the task queue? And will not fully excute until CP is accessed, unless you run the pending tasks manually?  I'm trying to run a plugin that updates externally loaded data from a cronjob (I used wget, not curl), and it seems not to work reliably. The problem may be elsewhere, but it works totally fine when running it manually from the CP at least.  

---

### Answer by username_4 on 2014-07-24. Score: 3

Ok, you are probably nearly there - all you need to do is call that controller action from the outside world. Here is a small example:
tasks->createTask('MyPlugin_Task');
    echo 'Task started!';
    craft()->end();
  }
}

Then you can access the url http://example.com/actions/myPlugin/someController/runSomeTask however you like. In cron you could then use something like wget to get the url:
0 2 * * * wget http://example.com/actions/myPlugin/someController/runSomeTask

All this information and more can be found in the docs: http://buildwithcraft.com/docs/plugins/controllers.
Edit:
I didn't really grasp the issue which is that Tasks only get set off when the cp is requested. To that end, one solution is to use something like PhantomJS to log in to the cp purely to start off the tasks. I have done this to actually set going something else more complex but here is a cleaned up example using PhantomJS and CasperJS to just access the cp and log in:
// make casper
var casper = require('casper').create();

// log in
casper.start('http://example.com/admin/login', function(){
  this.fill('#login-form', {
    'username' : 'someuser',
    'password' : 'somepassword'
  }, true);
});

// wait for the dashboard
casper.waitForUrl(http://example.com/admin/dashboard', function(){
  this.echo('Yay, logged in!');

  // maybe check for some evidence of the task running here

  casper.exit();
});

// tell casper to run the above sequence
casper.run();

I'm pretty sure at some point P&T will sort something more native out but for now this would work.

> **Comments:**
> **username_0**: Hi, thanks for the reply. I actually had the controller setup pretty much the same as you have shown. The only difference is that the task gets created from within the sendNotificationsEmail() function which is in the plugins service. I stripped things back to be like in your example but it seems that tasks only get processed the next time the CP is visited. Is there something I'm missing?  
> **username_4**: Ah, yes sorry - that is totally true. I just found where Brandon mentioned it on gplus: "you have to access the CP to trigger them in the first place (and even that is probably not going to be necessary down the road when I have a chance to test out an idea I have)" - see the comments here: https://plus.google.com/+LukeHolder/posts/Tc8w1Lr7Czw.  I'm not sure there is a way at present to ping the tasks save for logging into the cp. I have done this with PhantomJS though...  
> **username_0**: Thanks for the code for casperjs, never come across it before, I can see it being useful in the future. I did get it working as you suggested but then saw the answer from Mike which seem the more crafty way of doing things. Thanks for taking the time to respond to the question. I'm only 3 days into developing with Craft and I'm amazed by what can be achieved and the support of the community. I hope to be able to pitch in soon once I've got the hangs of things :)  
> **username_4**: Yeah, I completely failed to actually look at the TaskService since I first had a dig months back, which was silly really as P&T clearly have introduced those things they said they would! Best of luck with it all :)  
> **username_5**: Hi Josh? Any chance you d share more of the plugin using this casper js integration ? I am very interested by that but I am too much of a plugin dev dummy to make it.  
> **username_4**: Hey @migswd we've actually moved away from using CasperJS and are fully invested in Tasks now for this sort of things. But if you'd still like to see what we did I'm more than happy to share. Just drop me an email and I'll send you something on Monday - josh@supercooldesign.co.uk  

---

### Answer by username_6 on 2017-04-25. Score: 1

You may also want to register your route in your YourPlugin.php file, using the registerSiteRoutes method, example below:
public function registerSiteRoutes()
{
    return array(
        'myroute' => array('action' => 'myPlugin/myAction')
    );
}


---

### Answer by username_7 on 2017-06-17. Score: 1

I made a free plugin that may help. I had trouble running through http when there were many tasks.

The plugin executes tasks purely as cron (i.e. does not internally issue a curl or wget request).

I made the plugin available at:
<https://straightupcraft.com/craft-plugins/taskrunner>

or you can view the code at:
<https://gitlab.com/24hoursmedia/craft2-plugins/craft2-taskrunner>


---

