Closed (fixed)
Project:
Acquia DAM
Version:
1.1.x-dev
Component:
Code
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
3 Apr 2026 at 14:28 UTC
Updated:
11 May 2026 at 04:25 UTC
Jump to comment: Most recent
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.
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
Comment #3
rajeshreeputraComment #4
rajeshreeputraWhat was the issue / limitation
filterActiveAssets()stripped every search response item down to a bare[media_id => asset_id]map, discardingreleased_and_not_expired,deleted_date, andversion_idthat 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 assetgetFinalizedVersion()→getAssetVersions()— 1 API call per assetNote: 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).
The
search()call is made withinclude_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 whengetAsset()returned a 404, requiring a redundant individual API call per deleted asset.filterActiveAssets()returned a single flat[media_id => asset_id]array. Everything was routed throughcheckAssets(), 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
categorizeActiveAssets(array $items): array— replaces the flat return offilterActiveAssets(). Usesreleased_and_not_expiredanddeleted_datedirectly 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_dateset), expired, or unreleased assets.'update'→[media_id => asset_id]: released assets requiring metadata / file-property sync.fetchAndEnqueueAssets()—checkAssets()is bypassed entirely in the cron path. Two dedicated chunk loops replace the single loop:deleteCachedAssets()+ directsetUnpublished()->save()with full revision metadata (setNewRevision,setRevisionCreationTime,setRevisionLogMessage,setRevisionUserId(0)). No queue worker. NogetAsset()call.deleteCachedAssets()+ unconditionalcreateItem()for every released asset. Always enqueued — version comparison was intentionally omitted becauselastEditDateincludes metadata-only edits that must still triggerforceMappedFieldRefresh()in the queue worker.filterActiveAssets()— triggersE_USER_DEPRECATED, delegates tocategorizeActiveAssets(), scheduled for removal in acquia_dam:1.2.0.AssetUpdateCheckerdependency — property, constructor parameter, and assignment all removed.StringTranslationTraitadded for$this->t()in revision log messages.src/Client/AcquiaDamClient.phpNew
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.ymlDrupal\acquia_dam\Cron\Cron.@acquia_dam.asset_update_checkerargument removed fromacquia_dam.cronservice definition.acquia_dam.post_update.phpNew
acquia_dam_post_update_refresh_container_cronhook — empty post-update to force container rebuild ondrush updb, required because the service class path and constructor arguments both changed.Comment #8
rajeshreeputraMR merged!