Problem/Motivation

The customer is experiencing a recurring issue where assets deleted from the DAM—which have successfully moved to the "Pending Delete" dashboard—are failing to unpublish within the Drupal Media Library.

Issue fork acquia_dam-3583037

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

rajeshreeputra created an issue. See original summary.

rajeshreeputra’s picture

Status: Active » Needs review
rajeshreeputra’s picture

What was the issue / limitation

  1. Redundant API calls per cron run
    filterActiveAssets() stripped every search response item down to a bare [media_id => asset_id] map, discarding released_and_not_expired, deleted_date, and version_id that the API had already returned. checkAssets() then re-fetched this same data through two additional round-trips per asset:
    • getStatus()fetchAssetData()getAsset() — 1 API call per asset
    • getFinalizedVersion()getAssetVersions() — 1 API call per asset

    Note: the asset has been deleted from the DAM, so this will return a 404 and trigger a warning in Drupal.
    For a site with 50 updated assets per cron run (5 pages × 10): 105 API calls, where only 5 were actually necessary (one search per page).

  2. Deleted assets not detected upfront
    The search() call is made with include_deleted: true, meaning assets with a non-null deleted_date appear in the results. However, filterActiveAssets() made no use of that field. Deletion was only detected later when getAsset() returned a 404, requiring a redundant individual API call per deleted asset.
  3. No distinction between "must unpublish" and "must update" assets
    filterActiveAssets() returned a single flat [media_id => asset_id] array. Everything was routed through checkAssets(), which internally determined the action (unpublish vs. enqueue). This meant the status-determination API call (getAsset()) could not be eliminated even when the search response already carried the answer.

What was implemented / updated

  • New categorizeActiveAssets(array $items): array — replaces the flat return of filterActiveAssets(). Uses released_and_not_expired and deleted_date directly from the search payload to classify each asset into one of two groups with a single DB query and zero extra API calls:
    • 'unpublish'[media_id => asset_id]: deleted (deleted_date set), expired, or unreleased assets.
    • 'update'[media_id => asset_id]: released assets requiring metadata / file-property sync.
  • Refactored fetchAndEnqueueAssets()checkAssets() is bypassed entirely in the cron path. Two dedicated chunk loops replace the single loop:
    • Unpublish loop: deleteCachedAssets() + direct setUnpublished()->save() with full revision metadata (setNewRevision, setRevisionCreationTime, setRevisionLogMessage, setRevisionUserId(0)). No queue worker. No getAsset() call.
  • Update loop: deleteCachedAssets() + unconditional createItem() for every released asset. Always enqueued — version comparison was intentionally omitted because lastEditDate includes metadata-only edits that must still trigger forceMappedFieldRefresh() in the queue worker.
  • Deprecated filterActiveAssets() — triggers E_USER_DEPRECATED, delegates to categorizeActiveAssets(), scheduled for removal in acquia_dam:1.2.0.
  • Removed AssetUpdateChecker dependency — property, constructor parameter, and assignment all removed. StringTranslationTrait added for $this->t() in revision log messages.
  • Code coverage: test coverage for cron was missing so added tests to validate these scenarios.
  • src/Client/AcquiaDamClient.php
    New deleteCachedAssets(array $asset_ids): void — batches cache key deletion via $this->cacheBackend->deleteMultiple(). Called once per chunk instead of one-by-one.
  • acquia_dam.services.yml
    • Class updated to Drupal\acquia_dam\Cron\Cron.
    • @acquia_dam.asset_update_checker argument removed from acquia_dam.cron service definition.
  • acquia_dam.post_update.php
    New acquia_dam_post_update_refresh_container_cron hook — empty post-update to force container rebuild on drush updb, required because the service class path and constructor arguments both changed.

  • rajeshreeputra committed fff8c3a7 on 1.1.x
    Resolve #3583037 "Fix: Refactor Cron to use chunked asset categorization...

  • rajeshreeputra committed 886110e6 on 1.1.x
    Resolve #3583037 "Add test coverage for unpublish message in test."
    
rajeshreeputra’s picture

Status: Needs review » Fixed

MR merged!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.