Answers.Body: <p>The easiest solution for this would be either a special fieldvalue or a property in a <a href="https://www.yiiframework.com/doc/guide/2.0/en/concept-behaviors" rel="nofollow noreferrer">behavior</a> that you set in your job.</p>
  
  <pre class="lang-php prettyprint-override"><code>class MyJob extends BaseJob
  {
      public function execute($queue): bool
      {
          // do some api calls here
          // ....
          $entry-&gt;isSavedViaApi = true;
          $entry-&gt;setFieldValue('browsershotUrl', [$assetId]);
          Craft::$app-&gt;elements-&gt;saveElement($entry)
          // ....
      }
  }
  
  </code></pre>
  
  <p>and in your event, you can check against this property</p>
  
  <pre class="lang-php prettyprint-override"><code>Event::on(
    Elements::class,
    Elements::EVENT_BEFORE_SAVE_ELEMENT,
    function(Event $event) {
      $entry = $event-&gt;sender;
      if ($event-&gt;element instanceof \craft\elements\Entry) {
        $entry = $event-&gt;element;
        if (ElementHelper::isDraftOrRevision($entry)) {
          return;
        }
  
        if(($entry-&gt;sectionId == 18) &amp;&amp; ($entry-&gt;typeId == 26)) {
  
          // make sure to check the section first, because otherwise the entry
          // may not have this property of field
          if($entry-&gt;isSavedViaApi === true){
              return;
          }
          //
  
  
          $signpostURL = $entry-&gt;getFieldValue('signpostUrl');
          if(($signpostURL) &amp;&amp; ($signpostURL !== '')) {
            Craft::$app-&gt;queue-&gt;push(new BrowshotTask([
              'description' =&gt; 'Grabbing screenshot for '.$signpostURL,
              'url' =&gt; $signpostURL,
              'entryId' =&gt; $entry-&gt;id
            ]));
          }
        }
      }
    }
  );
  </code></pre>
  
  <p>If you want to use a behavior instead of a field value for this</p>
  
  <pre class="lang-php prettyprint-override"><code>use yii\base\Behavior;
  
  class MyBehavior extends Behavior
  {
      public $isSavedViaApi = false;
  }
  </code></pre>
  
  <p>and in your main module file</p>
  
  <pre class="lang-php prettyprint-override"><code>use craft\elements\Entry;
  use craft\events\DefineBehaviorsEvent;
  
  Event::on(
      Entry::class,
      Entry::EVENT_DEFINE_BEHAVIORS,
      static function(DefineBehaviorsEvent $event) {
          //so every element gets a isSubscribed attached
          $event-&gt;behaviors[] = MyBehavior::class;
      }
  );
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-11-08T09:57:47.453Z
Answers.LastActivityDate: 2019-11-08T09:57:47.453Z
Answers.UserDisplayName: Robin Schambach
Body: <p>I'm calling EVENT_BEFORE_SAVE_ELEMENT to trigger a task that then updates the entry, but it's causing a loop?</p>
  
  <p>The event is triggered when a specific entry type is saved:</p>
  
  <pre><code>Event::on(
    Elements::class,
    Elements::EVENT_BEFORE_SAVE_ELEMENT,
    function(Event $event) {
      $entry = $event-&gt;sender;
      if ($event-&gt;element instanceof \craft\elements\Entry) {
        $entry = $event-&gt;element;
        if (ElementHelper::isDraftOrRevision($entry)) {
          return;
        }
        if(($entry-&gt;sectionId == 18) &amp;&amp; ($entry-&gt;typeId == 26)) {
          $signpostURL = $entry-&gt;getFieldValue('signpostUrl');
          if(($signpostURL) &amp;&amp; ($signpostURL !== '')) {
            Craft::$app-&gt;queue-&gt;push(new BrowshotTask([
              'description' =&gt; 'Grabbing screenshot for '.$signpostURL,
              'url' =&gt; $signpostURL,
              'entryId' =&gt; $entry-&gt;id
            ]));
          }
        }
      }
    }
  );
  </code></pre>
  
  <p><code>BrowshotTask</code> then performs some API calls to a third-party service, gets a screenshot, saves an asset and saves the asset in the asset field of the entry.</p>
  
  <p>But this triggers the event again and causes a loop:</p>
  
  <pre><code>$entry-&gt;setFieldValue('browsershotUrl', [$assetId]);
  if(Craft::$app-&gt;elements-&gt;saveElement($entry)) {
  </code></pre>
  
  <p>Sometimes BrowshotTask can take 20 seconds due to the third-party service.. so I thought putting it in a task would be a great idea, but now it's causing me so many problems :(</p>
  
Tags: <entries><events><loop><tasks><queue>
Title: EVENT_BEFORE_SAVE_ELEMENT Saving element loop in task/queue
ThreadText: # EVENT_BEFORE_SAVE_ELEMENT Saving element loop in task/queue
  
  (Asked by: username_0 on 2019-11-07)
  
  I'm calling EVENT\_BEFORE\_SAVE\_ELEMENT to trigger a task that then updates the entry, but it's causing a loop?
  
  The event is triggered when a specific entry type is saved:
  
  ```
  Event::on(
    Elements::class,
    Elements::EVENT_BEFORE_SAVE_ELEMENT,
    function(Event $event) {
      $entry = $event->sender;
      if ($event->element instanceof \craft\elements\Entry) {
        $entry = $event->element;
        if (ElementHelper::isDraftOrRevision($entry)) {
          return;
        }
        if(($entry->sectionId == 18) && ($entry->typeId == 26)) {
          $signpostURL = $entry->getFieldValue('signpostUrl');
          if(($signpostURL) && ($signpostURL !== '')) {
            Craft::$app->queue->push(new BrowshotTask([
              'description' => 'Grabbing screenshot for '.$signpostURL,
              'url' => $signpostURL,
              'entryId' => $entry->id
            ]));
          }
        }
      }
    }
  );
  
  ```
  
  `BrowshotTask` then performs some API calls to a third-party service, gets a screenshot, saves an asset and saves the asset in the asset field of the entry.
  
  But this triggers the event again and causes a loop:
  
  ```
  $entry->setFieldValue('browsershotUrl', [$assetId]);
  if(Craft::$app->elements->saveElement($entry)) {
  
  ```
  
  Sometimes BrowshotTask can take 20 seconds due to the third-party service.. so I thought putting it in a task would be a great idea, but now it's causing me so many problems :(
  
  **Tags:** entries, events, loop, tasks, queue
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2019-11-08. Score: 2 | Accepted answer
  
  The easiest solution for this would be either a special fieldvalue or a property in a [behavior](https://www.yiiframework.com/doc/guide/2.0/en/concept-behaviors) that you set in your job.
  
  ```php
  class MyJob extends BaseJob
  {
      public function execute($queue): bool
      {
          // do some api calls here
          // ....
          $entry->isSavedViaApi = true;
          $entry->setFieldValue('browsershotUrl', [$assetId]);
          Craft::$app->elements->saveElement($entry)
          // ....
      }
  }
  
  ```
  
  and in your event, you can check against this property
  
  ```php
  Event::on(
    Elements::class,
    Elements::EVENT_BEFORE_SAVE_ELEMENT,
    function(Event $event) {
      $entry = $event->sender;
      if ($event->element instanceof \craft\elements\Entry) {
        $entry = $event->element;
        if (ElementHelper::isDraftOrRevision($entry)) {
          return;
        }
  
        if(($entry->sectionId == 18) && ($entry->typeId == 26)) {
  
          // make sure to check the section first, because otherwise the entry
          // may not have this property of field
          if($entry->isSavedViaApi === true){
              return;
          }
          //
  
          $signpostURL = $entry->getFieldValue('signpostUrl');
          if(($signpostURL) && ($signpostURL !== '')) {
            Craft::$app->queue->push(new BrowshotTask([
              'description' => 'Grabbing screenshot for '.$signpostURL,
              'url' => $signpostURL,
              'entryId' => $entry->id
            ]));
          }
        }
      }
    }
  );
  
  ```
  
  If you want to use a behavior instead of a field value for this
  
  ```php
  use yii\base\Behavior;
  
  class MyBehavior extends Behavior
  {
      public $isSavedViaApi = false;
  }
  
  ```
  
  and in your main module file
  
  ```php
  use craft\elements\Entry;
  use craft\events\DefineBehaviorsEvent;
  
  Event::on(
      Entry::class,
      Entry::EVENT_DEFINE_BEHAVIORS,
      static function(DefineBehaviorsEvent $event) {
          //so every element gets a isSubscribed attached
          $event->behaviors[] = MyBehavior::class;
      }
  );
  
  ```
  
  
  ---
  
  