Answers.Body: <p>Check out the example <a href="https://github.com/pixelandtonic/PowerNap" rel="nofollow">PowerNapTask</a> provided by Pixel &amp; Tonic — It implements a Task (and Subtask) with multiple steps. It should be fairly straightforward to modify that sample code to run your own custom logic.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-05T21:47:38.117Z
Answers.Text: I looked at the powernap plugin, but couldnt take that and turn it into what i needed, e.g. i have to send out an email to over a thousand users. Do i have the 1000 users loop within there being the email send in my run step with step set to 1?
Answers.UserDisplayName: BillyMedia
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-05T21:49:34.940Z
Answers.Text: And after each iteration, return true to trigger the next step?
Answers.UserDisplayName: BillyMedia
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-05T21:57:24.873Z
Answers.Text: @BillyMedia Yes, you would return true. You can structure it however you'd like.. Ideally, you would make every user a step within your task. That way you have some visual feedback as to how far along in the task process you are.
Answers.UserDisplayName: Chase Giunta
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-05T22:00:37.190Z
Answers.Text: If you're wanting to fire all these off at once in sequence (emails, query 3rd party api, etc.) you'll want to look into subtasks, also shown in the PowerNap plugin.
Answers.UserDisplayName: Chase Giunta
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-05T22:52:48.097Z
Answers.Text: Still a little confused as to how to send over 1000 emails? do I set getTotalSteps to a high number to allow the sending in chunks, then have a database query in runStep that sets a limit and an offset that sends out the emails?
Answers.UserDisplayName: BillyMedia
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-08-02T09:42:31.800Z
Answers.Text: You don't need steps, just create one task for each email.
Answers.UserDisplayName: MISC
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-05T21:41:54.770Z
Answers.LastActivityDate: 2016-04-05T21:41:54.770Z
Answers.UserDisplayName: Michael Rog
Answers.Body: <p>I'm following Brandon's example here but am having trouble passing the variable that is set from the first subtask to the second subtask. Here's my code:</p>
  
  <p><strong>Primary Task</strong></p>
  
  
  
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  namespace Craft;
  
  class Products_TestPrimaryTask extends BaseTask
  {
      public $myVar;
  
      public function getDescription()
      {
          return 'Running Primary Task';
      }
  
      public function getTotalSteps()
      {
          return 2;
      }
  
      public function runStep($step)
      {
          switch ($step)
          {
              case 0:
              {
                  return $this-&gt;runSubTask('Products_TestSub1', null, array(
                      'primaryTaskId' =&gt; $this-&gt;model-&gt;id
                  ));
              }
              case 1:
              {
                  return $this-&gt;runSubTask('Products_TestSub2', null, array(
                      'subVar' =&gt; $this-&gt;myVar,
                  ));
              }
          }
  
          return true;
      }
  
      public function setPrimaryTaskVar($var)
      {
          $this-&gt;myVar = $var;
  
          ProductsPlugin::log('Variable in Primary Task: ' . print_r($this-&gt;myVar, true));
      }
  }
  </code></pre>
  
  <p><strong>Sub Task 1</strong></p>
  
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  namespace Craft;
  
  class Products_TestSub1Task extends BaseTask
  {
      protected function defineSettings()
      {
          return [
              'primaryTaskId' =&gt; AttributeType::Number
          ];
      }
  
      public function getDescription()
      {
          return 'Running Sub Task 1';
      }
  
      public function getTotalSteps()
      {
          return 1;
      }
  
      public function runStep($step)
      {
          $primaryTask = craft()-&gt;tasks-&gt;getTaskById($this-&gt;getSettings()-&gt;primaryTaskId);
          $primaryTask-&gt;getTaskType()-&gt;setPrimaryTaskVar('hello');
  
          return true;
      }
  }
  </code></pre>
  
  <p><strong>Sub Task 2</strong></p>
  
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  namespace Craft;
  
  class Products_TestSub2Task extends BaseTask
  {
      protected function defineSettings()
      {
          return [
              'subVar' =&gt; AttributeType::String
          ];
      }
  
      public function getDescription()
      {
          return 'Running Sub Task 2';
      }
  
      public function getTotalSteps()
      {
          return 1;
      }
  
      public function runStep($step)
      {
          ProductsPlugin::log('Variable in Sub Task 2: ' . print_r($this-&gt;getSettings()-&gt;subVar, true));
  
          return true;
      }
  }
  </code></pre>
  
  <p>So Sub Task 1 calls the <code>setPrimaryTaskVar</code> method in the Primary Task, which sets the variable that then gets passed to Sub Task 2 in step 2 of the Primary Task. However, when I try to log that variable in Sub Task 2 it is showing as null.</p>
  
  <p>Am I missing something obvious here?</p>
  
  <p><strong>WORKAROUND</strong></p>
  
  <p>After playing around with this a bit more, the only way I could persist the data between steps in the Primary Task was to save the variable in question to a SESSION var. So the Primary Task class has been amended to the following. Hope this helps someone else:</p>
  
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  namespace Craft;
  
  class Products_TestPrimaryTask extends BaseTask
  {
      /**
       * Returns the default description for this task.
       *
       * @return string
       */
      public function getDescription()
      {
          return 'Running Primary Task';
      }
  
      /**
       * Gets the total number of steps for this task.
       *
       * @return int
       */
      public function getTotalSteps()
      {
          return 2;
      }
  
      /**
       * Runs a task step.
       *
       * @param int $step
       * @return bool
       */
      public function runStep($step)
      {
          switch ($step)
          {
              case 0:
              {
                  return $this-&gt;runSubTask('Products_TestSub1', null, array(
                      'primaryTaskId' =&gt; $this-&gt;model-&gt;id
                  ));
              }
              case 1:
              {
                  return $this-&gt;runSubTask('Products_TestSub2', null, array(
                      'subVar' =&gt; $_SESSION['subVar']
                  ));
              }
          }
  
          return true;
      }
  
      public function setPrimaryTaskVar($var)
      {
          $_SESSION['subVar'] = $var;
  
          ProductsPlugin::log('Variable in Primary Task: ' . print_r($_SESSION['subVar'], true));
      }
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-11T12:21:28.417Z
Answers.LastActivityDate: 2017-09-11T13:03:00.853Z
Answers.LastEditDate: 2017-09-11T13:03:00.853Z
Answers.UserDisplayName: Paul Goodfield
Answers.Body: <p>You can implement your entire Task with a single step if you want. The only point of breaking it into multiple steps is so the task progress bar has an idea of how far along the task is.</p>
  
  <p>In your case, since your task is broken up into multiple unrelated processes, you might want to implement it with subtasks. So the top-level task only has a couple of steps based on the different high-level aspects of the task, and create separate task classes for those individual steps.</p>
  
  <p>So let's say you have two main steps:</p>
  
  <ul>
  <li>call an external API</li>
  <li>send emails</li>
  </ul>
  
  <p>and (I’m guessing, just to illustrate how this could work), let’s say that the email recipients are being determined by that API call, so you need a little bit of cross-communication between those processes.</p>
  
  <p>Here’s the gist of how you’d set those classes up:</p>
  
  <p><strong>Primary task class</strong></p>
  
  
  
  <pre class="lang-php prettyprint-override"><code>class MyPlugin_PrimaryTask extends BaseTask
  {
      private $_emails;
  
      public function getDescription()
      {
          return 'Blasting emails';
      }
  
      public function getTotalSteps()
      {
          return 2;
      }
  
      public function runStep($step)
      {
          switch ($step)
          {
              case 0:
              {
                  return $this-&gt;runSubTask('MyPlugin_ApiTask', null, array(
                      'primaryTaskId' =&gt; $this-&gt;model-&gt;id
                  ));
              }
              case 1:
              {
                  return $this-&gt;runSubTask('MyPlugin_EmailTask', null, array(
                      'emails' =&gt; $this-&gt;_emails;
                  ));
              }
          }
      }
  
      public function setEmails($emails)
      {
          $this-&gt;_emails = $emails;
      }
  }
  </code></pre>
  
  <p><strong>API-calling task</strong></p>
  
  <pre class="lang-php prettyprint-override"><code>class MyPlugin_ApiTask extends BaseTask
  {
      private $_parentTask;
      private $_emails;
  
      public function getDescription()
      {
          return 'Calling the external API';
      }
  
      public function getTotalSteps()
      {
          return 1;
      }
  
      public function runStep($step)
      {
          // Call the API and get a list of emails
          // ...
          // $emails = ...
  
          // Pass the emails along to the primary task
          $primaryTask = craft()-&gt;tasks-&gt;getTaskById($this-&gt;getSettings()-&gt;primaryTaskId);
          $primaryTask-&gt;getTaskType()-&gt;setEmails($emails);
  
          return true;
      }
  
      protected function defineSettings()
      {
          return array(
              'primaryTaskId' =&gt; AttributeType::Number
          );
      }
  }
  </code></pre>
  
  <p><strong>Email-sending task</strong></p>
  
  <pre class="lang-php prettyprint-override"><code>class MyPlugin_EmailTask extends BaseTask
  {
      public function getDescription()
      {
          return 'Sending the emails';
      }
  
      public function getTotalSteps()
      {
          return count($this-&gt;getSettings()-&gt;emails);
      }
  
      public function runStep($step)
      {
          $email = new EmailModel();
          $email-&gt;toEmail = $this-&gt;getSettings()-&gt;emails[$step];
          $email-&gt;subject = '...';
          $email-&gt;body = '...';
          craft()-&gt;email-&gt;sendEmail($email);
  
          return true;
      }
  
      protected function defineSettings()
      {
          return array(
              'emails' =&gt; AttributeType::Mixed
          );
      }
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-06T07:58:41.090Z
Answers.Text: And taking my scenario, would i use sql limit and offset using the $step argument to break it into steps?
Answers.UserDisplayName: BillyMedia
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-06T10:14:28.653Z
Answers.Text: @BillyMedia Just updated my answer with an example of how you might set this up, based on your question.
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-05T23:31:52.707Z
Answers.LastActivityDate: 2016-04-06T10:13:55.637Z
Answers.LastEditDate: 2016-04-06T10:13:55.637Z
Answers.UserDisplayName: Brandon Kelly
Body: <p>I need to implement a bunch of background processes that do things like send emails, query 3rd pary api etc. </p>
  
  <p>I have the task in place, but i dont fully understand how steps work, docs are a little thin on this, can someone explain how this works?</p>
  
Tags: <plugin-development><plugins>
Title: Tasks and Steps
ThreadText: # Tasks and Steps
  
  (Asked by: username_0 on 2016-04-05)
  
  I need to implement a bunch of background processes that do things like send emails, query 3rd pary api etc.
  
  I have the task in place, but i dont fully understand how steps work, docs are a little thin on this, can someone explain how this works?
  
  **Tags:** plugin-development, plugins
  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_5 on 2016-04-05. Score: 11 | Accepted answer
  
  You can implement your entire Task with a single step if you want. The only point of breaking it into multiple steps is so the task progress bar has an idea of how far along the task is.
  
  In your case, since your task is broken up into multiple unrelated processes, you might want to implement it with subtasks. So the top-level task only has a couple of steps based on the different high-level aspects of the task, and create separate task classes for those individual steps.
  
  So let's say you have two main steps:
  
  * call an external API
  * send emails
  
  and (I’m guessing, just to illustrate how this could work), let’s say that the email recipients are being determined by that API call, so you need a little bit of cross-communication between those processes.
  
  Here’s the gist of how you’d set those classes up:
  
  **Primary task class**
  
  ```php
  class MyPlugin_PrimaryTask extends BaseTask
  {
      private $_emails;
  
      public function getDescription()
      {
          return 'Blasting emails';
      }
  
      public function getTotalSteps()
      {
          return 2;
      }
  
      public function runStep($step)
      {
          switch ($step)
          {
              case 0:
              {
                  return $this->runSubTask('MyPlugin_ApiTask', null, array(
                      'primaryTaskId' => $this->model->id
                  ));
              }
              case 1:
              {
                  return $this->runSubTask('MyPlugin_EmailTask', null, array(
                      'emails' => $this->_emails;
                  ));
              }
          }
      }
  
      public function setEmails($emails)
      {
          $this->_emails = $emails;
      }
  }
  
  ```
  
  **API-calling task**
  
  ```php
  class MyPlugin_ApiTask extends BaseTask
  {
      private $_parentTask;
      private $_emails;
  
      public function getDescription()
      {
          return 'Calling the external API';
      }
  
      public function getTotalSteps()
      {
          return 1;
      }
  
      public function runStep($step)
      {
          // Call the API and get a list of emails
          // ...
          // $emails = ...
  
          // Pass the emails along to the primary task
          $primaryTask = craft()->tasks->getTaskById($this->getSettings()->primaryTaskId);
          $primaryTask->getTaskType()->setEmails($emails);
  
          return true;
      }
  
      protected function defineSettings()
      {
          return array(
              'primaryTaskId' => AttributeType::Number
          );
      }
  }
  
  ```
  
  **Email-sending task**
  
  ```php
  class MyPlugin_EmailTask extends BaseTask
  {
      public function getDescription()
      {
          return 'Sending the emails';
      }
  
      public function getTotalSteps()
      {
          return count($this->getSettings()->emails);
      }
  
      public function runStep($step)
      {
          $email = new EmailModel();
          $email->toEmail = $this->getSettings()->emails[$step];
          $email->subject = '...';
          $email->body = '...';
          craft()->email->sendEmail($email);
  
          return true;
      }
  
      protected function defineSettings()
      {
          return array(
              'emails' => AttributeType::Mixed
          );
      }
  }
  
  ```
  
  > **Comments:**
  > **username_0**: And taking my scenario, would i use sql limit and offset using the $step argument to break it into steps?  
  > **username_5**: @username_0 Just updated my answer with an example of how you might set this up, based on your question.  
  
  ---
  
  ### Answer by username_1 on 2016-04-05. Score: 2
  
  Check out the example [PowerNapTask](https://github.com/pixelandtonic/PowerNap) provided by Pixel & Tonic — It implements a Task (and Subtask) with multiple steps. It should be fairly straightforward to modify that sample code to run your own custom logic.
  
  > **Comments:**
  > **username_0**: I looked at the powernap plugin, but couldnt take that and turn it into what i needed, e.g. i have to send out an email to over a thousand users. Do i have the 1000 users loop within there being the email send in my run step with step set to 1?  
  > **username_0**: And after each iteration, return true to trigger the next step?  
  > **username_2**: @username_0 Yes, you would return true. You can structure it however you'd like.. Ideally, you would make every user a step within your task. That way you have some visual feedback as to how far along in the task process you are.  
  > **username_2**: If you're wanting to fire all these off at once in sequence (emails, query 3rd party api, etc.) you'll want to look into subtasks, also shown in the PowerNap plugin.  
  > **username_0**: Still a little confused as to how to send over 1000 emails? do I set getTotalSteps to a high number to allow the sending in chunks, then have a database query in runStep that sets a limit and an offset that sends out the emails?  
  > **username_3**: You don't need steps, just create one task for each email.  
  
  ---
  
  ### Answer by username_4 on 2017-09-11. Score: 1
  
  I'm following username_5's example here but am having trouble passing the variable that is set from the first subtask to the second subtask. Here's my code:
  
  **Primary Task**
  
  ```php
  <?php
  namespace Craft;
  
  class Products_TestPrimaryTask extends BaseTask
  {
      public $myVar;
  
      public function getDescription()
      {
          return 'Running Primary Task';
      }
  
      public function getTotalSteps()
      {
          return 2;
      }
  
      public function runStep($step)
      {
          switch ($step)
          {
              case 0:
              {
                  return $this->runSubTask('Products_TestSub1', null, array(
                      'primaryTaskId' => $this->model->id
                  ));
              }
              case 1:
              {
                  return $this->runSubTask('Products_TestSub2', null, array(
                      'subVar' => $this->myVar,
                  ));
              }
          }
  
          return true;
      }
  
      public function setPrimaryTaskVar($var)
      {
          $this->myVar = $var;
  
          ProductsPlugin::log('Variable in Primary Task: ' . print_r($this->myVar, true));
      }
  }
  
  ```
  
  **Sub Task 1**
  
  ```php
  <?php
  namespace Craft;
  
  class Products_TestSub1Task extends BaseTask
  {
      protected function defineSettings()
      {
          return [
              'primaryTaskId' => AttributeType::Number
          ];
      }
  
      public function getDescription()
      {
          return 'Running Sub Task 1';
      }
  
      public function getTotalSteps()
      {
          return 1;
      }
  
      public function runStep($step)
      {
          $primaryTask = craft()->tasks->getTaskById($this->getSettings()->primaryTaskId);
          $primaryTask->getTaskType()->setPrimaryTaskVar('hello');
  
          return true;
      }
  }
  
  ```
  
  **Sub Task 2**
  
  ```php
  <?php
  namespace Craft;
  
  class Products_TestSub2Task extends BaseTask
  {
      protected function defineSettings()
      {
          return [
              'subVar' => AttributeType::String
          ];
      }
  
      public function getDescription()
      {
          return 'Running Sub Task 2';
      }
  
      public function getTotalSteps()
      {
          return 1;
      }
  
      public function runStep($step)
      {
          ProductsPlugin::log('Variable in Sub Task 2: ' . print_r($this->getSettings()->subVar, true));
  
          return true;
      }
  }
  
  ```
  
  So Sub Task 1 calls the `setPrimaryTaskVar` method in the Primary Task, which sets the variable that then gets passed to Sub Task 2 in step 2 of the Primary Task. However, when I try to log that variable in Sub Task 2 it is showing as null.
  
  Am I missing something obvious here?
  
  **WORKAROUND**
  
  After playing around with this a bit more, the only way I could persist the data between steps in the Primary Task was to save the variable in question to a SESSION var. So the Primary Task class has been amended to the following. Hope this helps someone else:
  
  ```php
  <?php
  namespace Craft;
  
  class Products_TestPrimaryTask extends BaseTask
  {
      /**
       * Returns the default description for this task.
       *
       * @return string
       */
      public function getDescription()
      {
          return 'Running Primary Task';
      }
  
      /**
       * Gets the total number of steps for this task.
       *
       * @return int
       */
      public function getTotalSteps()
      {
          return 2;
      }
  
      /**
       * Runs a task step.
       *
       * @param int $step
       * @return bool
       */
      public function runStep($step)
      {
          switch ($step)
          {
              case 0:
              {
                  return $this->runSubTask('Products_TestSub1', null, array(
                      'primaryTaskId' => $this->model->id
                  ));
              }
              case 1:
              {
                  return $this->runSubTask('Products_TestSub2', null, array(
                      'subVar' => $_SESSION['subVar']
                  ));
              }
          }
  
          return true;
      }
  
      public function setPrimaryTaskVar($var)
      {
          $_SESSION['subVar'] = $var;
  
          ProductsPlugin::log('Variable in Primary Task: ' . print_r($_SESSION['subVar'], true));
      }
  }
  
  ```
  
  
  ---
  
  