{"id":45957,"date":"2017-02-14T17:04:06","date_gmt":"2017-02-14T11:34:06","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=45957"},"modified":"2017-02-14T17:04:06","modified_gmt":"2017-02-14T11:34:06","slug":"how-to-implement-queue-workerapi-in-drupal-8","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/how-to-implement-queue-workerapi-in-drupal-8\/","title":{"rendered":"How to implement Queue Worker\/API in Drupal 8?"},"content":{"rendered":"<p>Before I start my writing about Queue Worker, it is important to understand about cron job in <a title=\"Drupal development\" href=\"http:\/\/www.tothenew.com\/wcm\/drupal-development-consulting-services\">Drupal<\/a> 8.<\/p>\n<p>In generic terms, cron is a scheduled job which runs periodically at fixed intervals. cron manages typical tasks such as database maintenance, sending bulk emails, fetching data from a\u00a0third-party on regular basis.<\/p>\n<p>It manages short running tasks with fewer resources and it will automatically time-out while performing\u00a0time-consuming tasks such as fetching data from a\u00a0third- party.<\/p>\n<p>In Drupal you can write cron like:-<\/p>\n<p>[php]<\/p>\n<p>function hook_cron() {<br \/>\n\u00a0 \/\/code.<br \/>\n}<\/p>\n<p>[\/php]<\/p>\n<p>in .module file of your module.<\/p>\n<p>So let&#8217;s take an example:-<br \/>\nThere is a module namely &#8211; my_module.<br \/>\nso in my_module.module file write<\/p>\n<p>[php]<\/p>\n<p>function my_module_cron() {<br \/>\n $mailManager = \\Drupal::service(&#8216;plugin.manager.mail&#8217;);<br \/>\n $mailManager-&gt;mail($module, $key, $to, $langcode, $params = array(), $reply = NULL, $send = TRUE);<br \/>\n}<\/p>\n<p>\/**<br \/>\n * Implements hook_mail().<br \/>\n *\/<br \/>\nfunction my_module_mail($key, &amp;$message, $params) {<br \/>\n switch ($key) {<br \/>\n case &#8216;key&#8217;:<br \/>\n $message[&#8216;subject&#8217;] = t(&#8216;Test&#8217;);<br \/>\n $message[&#8216;body&#8217;][] = &#8216;Hello World!&#8217;;<br \/>\n break;<br \/>\n }<br \/>\n}<\/p>\n<p>[\/php]<\/p>\n<p>Whenever cron is executed it will send an email.<\/p>\n<p>drush commands to run a cron manually.<\/p>\n<p>drush core-cron<\/p>\n<p>alias<\/p>\n<p>drush cron<\/p>\n<p><strong>Disadvantages:-<\/strong><\/p>\n<ol>\n<li>You can not run an individual cron.<\/li>\n<li>All hook_cron runs at same time for all modules according to module weight<br \/>\nQueue Worker A Powerful manual cron system.<\/li>\n<li>When\u00a0cron fails for a\u00a0module, the other cron of different modules will be not executed.<\/li>\n<li>There is no logging information that can tell us which module was the culprit for cron failure.<\/li>\n<li>Cron can&#8217;t handle large and complex tasks in huge quantity.<\/li>\n<li>You can&#8217;t run cron with time limits.<\/li>\n<\/ol>\n<p><strong>QueueWorker:-<\/strong><\/p>\n<p>The following disadvantages compel us to use queue API of Drupal 8 which is known as Queue Worker.<\/p>\n<p><span style=\"color: #333333\">Queue Worker offers a lot of advantages such <\/span>as :<\/p>\n<ol>\n<li>Offers flexibility to run queue with time limits<\/li>\n<li>You can individual queue at one time as compared to cron which runs all the cron<\/li>\n<li>Efficient as compared to cron, can handle resource intensive tasks<\/li>\n<li>If any\u00a0failure occurs, you can revert the item\u00a0back to queue to process that again<\/li>\n<li>Multiple queues can run without interrupting other work<\/li>\n<li>You can log for each item of queue easily<\/li>\n<\/ol>\n<p>Queue Worker rules out the disadvantage of hook_cron and hence solve the issues with hook cron very efficiently.<\/p>\n<p>Here are some of the basics concepts of Queue API along with an example:<\/p>\n<p>The Queue API in Drupal allows you to complete tasks at a\u00a0later stage. We can insert items in the queue and process them when we require. We can run Queue either by running cron or by manually using Drush commands.<\/p>\n<p>Some very basic concepts of Queue working is\u00a0FIFO.<\/p>\n<p>Components of Queue API.<\/p>\n<ol>\n<li><strong>QueueInterface<\/strong>:-\n<ul>\n<li>It plays a very important role here. Its implementation represents queue, which means the object of a class that implements\u00a0QueueInterface.<\/li>\n<\/ul>\n<\/li>\n<li><strong>DatabaseQueue<\/strong>:-\n<ul>\n<li>It is a reliable type of queue which\u00a0makes ensure that it does not timeout. All the items are processed without any error and in (FIFO) order.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Roles of Queue Object<\/strong>:-\n<ul>\n<li>The typical role of the queue object is to create items, claim them from the queue and delete them when they have been processed.<\/li>\n<li>You can also release the items if processing is not finished or another Queue\u00a0needs to be processed before removing them from Queue.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>Here&#8217;s an example of Queue Worker.<\/p>\n<p>You have a user query form on your website. See the attached screenshot of Form.\u00a0<span style=\"font-size: 1rem\">So, whenever a\u00a0<\/span>user<span style=\"font-size: 1rem\"> submits a query instead of sending mail at run-time we will store these details in Queue Worker and later run Queue Worker manually whenever we want to receive emails.<\/span><\/p>\n<p>Folder Structure. See attached screenshot.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-46101 size-full\" src=\"\/blog\/wp-ttn-blog\/uploads\/2017\/02\/110.png\" alt=\"1\" width=\"962\" height=\"363\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2017\/02\/110.png 962w, \/blog\/wp-ttn-blog\/uploads\/2017\/02\/110-300x113.png 300w, \/blog\/wp-ttn-blog\/uploads\/2017\/02\/110-624x235.png 624w\" sizes=\"(max-width: 962px) 100vw, 962px\" \/><\/p>\n<p>my_module.info.yml<\/p>\n<p>[php]<\/p>\n<p>name: My Module<br \/>\ndescription: &#8216;Example how to use Queue Worker&#8217;<br \/>\npackage: Custom<br \/>\ntype: module<br \/>\ncore: 8.x<\/p>\n<p>[\/php]<\/p>\n<p>my_module.routing.yml<\/p>\n<p>[php]<\/p>\n<p>my_module.query_form:<br \/>\n path: &#8216;\/user-query-form&#8217;<br \/>\n defaults:<br \/>\n _form: &#8216;\\Drupal\\my_module\\Form\\UserQueryForm&#8217;<br \/>\n _title: &#8216;Query Form&#8217;<br \/>\n requirements:<br \/>\n _permission: &#8216;access content&#8217;<\/p>\n<p>[\/php]<\/p>\n<p>UserQueryForm.php<\/p>\n<p>Screenshot:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-45971 size-full\" src=\"\/blog\/wp-ttn-blog\/uploads\/2017\/02\/form.png\" alt=\"form\" width=\"645\" height=\"244\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2017\/02\/form.png 645w, \/blog\/wp-ttn-blog\/uploads\/2017\/02\/form-300x113.png 300w, \/blog\/wp-ttn-blog\/uploads\/2017\/02\/form-624x236.png 624w\" sizes=\"(max-width: 645px) 100vw, 645px\" \/><\/p>\n<p>Code:-<\/p>\n<p>[php]<\/p>\n<p>&lt;?php<\/p>\n<p>namespace Drupal\\my_module\\Form;<\/p>\n<p>use Drupal\\Core\\Form\\FormBase;<br \/>\nuse Drupal\\Core\\Form\\FormStateInterface;<\/p>\n<p>\/**<br \/>\n * Class UserQueryForm.<br \/>\n *<br \/>\n * @package Drupal\\my_module\\Form<br \/>\n *\/<br \/>\nclass UserQueryForm extends FormBase {<\/p>\n<p>\/**<br \/>\n * {@inheritdoc}<br \/>\n *\/<br \/>\n public function getFormId() {<br \/>\n return &#8216;user_query_form&#8217;;<br \/>\n }<\/p>\n<p>\/**<br \/>\n * {@inheritdoc}<br \/>\n *\/<br \/>\n public function buildForm(array $form, FormStateInterface $form_state) {<br \/>\n $form[&#8216;name&#8217;] = [<br \/>\n &#8216;#type&#8217; =&gt; &#8216;textfield&#8217;,<br \/>\n &#8216;#attributes&#8217; =&gt; [<br \/>\n &#8216;placeholder&#8217; =&gt; &#8216;Username&#8217;,<br \/>\n ],<br \/>\n &#8216;#required&#8217; =&gt; true,<br \/>\n ];<br \/>\n $form[&#8217;email&#8217;] = [<br \/>\n &#8216;#type&#8217; =&gt; &#8217;email&#8217;,<br \/>\n &#8216;#attributes&#8217; =&gt; [<br \/>\n &#8216;placeholder&#8217; =&gt; &#8216;Email&#8217;,<br \/>\n ],<br \/>\n &#8216;#required&#8217; =&gt; true,<br \/>\n ];<br \/>\n $form[&#8216;query&#8217;] = [<br \/>\n &#8216;#type&#8217; =&gt; &#8216;textarea&#8217;,<br \/>\n &#8216;#attributes&#8217; =&gt; [<br \/>\n &#8216;placeholder&#8217; =&gt; &#8216;Query&#8217;,<br \/>\n ],<br \/>\n &#8216;#description&#8217; =&gt; &#8216;Upto 200 characters allowed&#8217;,<br \/>\n &#8216;#required&#8217; =&gt; true,<br \/>\n ];<br \/>\n $form[&#8216;submit&#8217;] = [<br \/>\n &#8216;#type&#8217; =&gt; &#8216;submit&#8217;,<br \/>\n &#8216;#value&#8217; =&gt; &#8216;Send&#8217;,<\/p>\n<p> ];<br \/>\n return $form;<br \/>\n }<\/p>\n<p>\/**<br \/>\n * {@inheritdoc}<br \/>\n *\/<br \/>\n public function validateForm(array &amp;$form, FormStateInterface $form_state) {<\/p>\n<p>}<\/p>\n<p>\/**<br \/>\n * {@inheritdoc}<br \/>\n *\/<br \/>\n public function submitForm(array &amp;$form, FormStateInterface $form_state) {<br \/>\n \/** @var QueueFactory $queue_factory *\/<br \/>\n $queue_factory = \\Drupal::service(&#8216;queue&#8217;);<br \/>\n \/** @var QueueInterface $queue *\/<br \/>\n $queue = $queue_factory-&gt;get(&#8217;email_processor&#8217;);<br \/>\n $item = new \\stdClass();<br \/>\n $item-&gt;username = $form_state-&gt;getValue(&#8216;name&#8217;);<br \/>\n $item-&gt;email = $form_state-&gt;getValue(&#8217;email&#8217;);<br \/>\n $item-&gt;query = $form_state-&gt;getValue(&#8216;query&#8217;);<br \/>\n $queue-&gt;createItem($item);<br \/>\n }<br \/>\n}<\/p>\n<p>[\/php]<\/p>\n<p>First create\u00a0<code class=\" language-undefined\">QueueFactory<\/code>\u00a0object from the service container statically and use this object to instantiate a queue object of email_proceesor.<\/p>\n<p>Here\u00a0we are calling createItem() function to insert items in Queue.<\/p>\n<p>So, whenever a user submits query form an item will be inserted in the Queue.<\/p>\n<p>To see the items in Queue use this drush command:<\/p>\n<p>drush queue-list<\/p>\n<p>EmailEventBase.php<\/p>\n<p><strong>The Queue Worker<\/strong><\/p>\n<p>The Queue Worker is Plugin so we create\u00a0EmailEventBase.php inside Plugin Folder as attached screenshot of folder structure.<\/p>\n<p>[php]<\/p>\n<p>&lt;?php<\/p>\n<p>\/**<br \/>\n * Handles sending of email.<br \/>\n *<br \/>\n * PHP Version 5<br \/>\n *\/<\/p>\n<p>namespace Drupal\\my_module\\Plugin\\QueueWorker;<\/p>\n<p>use Drupal\\Core\\Plugin\\ContainerFactoryPluginInterface;<br \/>\nuse Drupal\\Core\\Queue\\QueueWorkerBase;<br \/>\nuse Drupal\\Core\\Mail\\MailManager;<br \/>\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;<\/p>\n<p>\/**<br \/>\n *<br \/>\n * @inheritdoc<br \/>\n *\/<br \/>\nclass EmailEventBase extends QueueWorkerBase implements ContainerFactoryPluginInterface {<\/p>\n<p> \/**<br \/>\n *<br \/>\n * @var Drupal\\Core\\Mail\\MailManager<br \/>\n *\/<br \/>\n protected $mail;<br \/>\n \/**<br \/>\n * constructor<br \/>\n *\/<br \/>\n public function __construct(MailManager $mail) {<br \/>\n $this-&gt;mail = $mail;<br \/>\n }<\/p>\n<p>\/**<br \/>\n * {@inheritdoc}<br \/>\n *\/<br \/>\n public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {<br \/>\n return new static(<br \/>\n $container-&gt;get(&#8216;plugin.manager.mail&#8217;)<br \/>\n );<br \/>\n }<\/p>\n<p>\/**<br \/>\n * Processes a single item of Queue.<br \/>\n *<br \/>\n *\/<br \/>\n public function processItem($data) {<br \/>\n $params[&#8216;subject&#8217;] = t(&#8216;query&#8217;);<br \/>\n $params[&#8216;message&#8217;] = $data-&gt;query;<br \/>\n $params[&#8216;from&#8217;] = $data-&gt;email;<br \/>\n $params[&#8216;username&#8217;] = $data-&gt;username;<br \/>\n $to = \\Drupal::config(&#8216;system.site&#8217;)-&gt;get(&#8216;mail&#8217;);<br \/>\n $this-&gt;mail-&gt;mail(&#8216;my_module&#8217;,&#8217;query_mail&#8217;,$to,&#8217;en&#8217;,$params,NULL,true);<br \/>\n }<br \/>\n}<\/p>\n<p>[\/php]<\/p>\n<p>In processItem() function we are processing individual\u00a0items of Queue.<\/p>\n<p>Now, let\u2019s create a CronEventProcessor\u00a0plugin that will use this logic on Cron runs or when we will run manually using drush command:<\/p>\n<p>CronEventProcessor.php<\/p>\n<p>[php]<\/p>\n<p>&lt;?php<br \/>\n\/**<br \/>\n *<br \/>\n * PHP Version 5<br \/>\n *\/<\/p>\n<p>namespace Drupal\\my_module\\Plugin\\QueueWorker;<\/p>\n<p>\/**<br \/>\n *<br \/>\n * @QueueWorker(<br \/>\n * id = &quot;email_processor&quot;,<br \/>\n * title = &quot;My custom Queue Worker&quot;,<br \/>\n * cron = {&quot;time&quot; = 10}<br \/>\n * )<br \/>\n *\/<br \/>\nclass CronEventProcessor extends EmailEventBase {<\/p>\n<p>}<\/p>\n<p>[\/php]<\/p>\n<p>In this file, we have written annotation. So by writing annotation, we are telling Drupal that whenever cron runs process this queue for 10 seconds.<\/p>\n<p>Whenever cron runs Queue Worker will load all the plugins that cron as their key in annotations. The id in annotation is user for creating object of queue.<\/p>\n<p>in .module file of your module you need to write hook_mail to send mail.<\/p>\n<p>[php]<\/p>\n<p>&lt;?php<\/p>\n<p>\/**<br \/>\n * Implements hook_mail()<br \/>\n * @param type $key<br \/>\n * @param type $message<br \/>\n * @param type $params<br \/>\n *\/<br \/>\nfunction my_module_mail($key, &amp;$message, $params) {<br \/>\n switch ($key) {<br \/>\n case &#8216;query_mail&#8217;:<br \/>\n $body = &quot;Hi &quot;.$params[&#8216;username&#8217;]<br \/>\n . &quot; Thanks for posting your Query&quot;<br \/>\n . $params[&#8216;message&#8217;]<br \/>\n . &quot;Your username: &quot; . $params[&#8216;username&#8217;]<\/p>\n<p> . &quot;Your email: &quot; . $params[&#8217;email&#8217;];<\/p>\n<p> $message[&#8216;from&#8217;] = $params[&#8216;from&#8217;];<br \/>\n $message[&#8216;subject&#8217;] = $params[&#8216;subject&#8217;];<br \/>\n $message[&#8216;body&#8217;][] = Drupal\\Core\\Mail\\MailFormatHelper::htmlToText($body);<br \/>\n break;<br \/>\n }<br \/>\n}<\/p>\n<p>[\/php]<\/p>\n<p>To run this queue manually we can use drush command like:-<\/p>\n<p><span class=\"il\">drush<\/span> queue-run email_processor\u00a0&#8211;time-limit=10<\/p>\n<p>Conclusion:-<\/p>\n<p>You should use Queue API instead of native hook_cron(). It has many benefits as compared to hook_cron.<\/p>\n<p>Manage your resource intensive tasks on your website using Queue API.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Before I start my writing about Queue Worker, it is important to understand about cron job in Drupal 8. In generic terms, cron is a scheduled job which runs periodically at fixed intervals. cron manages typical tasks such as database maintenance, sending bulk emails, fetching data from a\u00a0third-party on regular basis. It manages short running [&hellip;]<\/p>\n","protected":false},"author":1058,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":152},"categories":[3602,1],"tags":[4862,4423],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/45957"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1058"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=45957"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/45957\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=45957"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=45957"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=45957"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}