aminghadersohi commented on code in PR #38576:
URL: https://github.com/apache/superset/pull/38576#discussion_r3482421515


##########
superset/utils/screenshots.py:
##########
@@ -280,43 +281,66 @@ def compute_and_cache(  # pylint: 
disable=too-many-arguments
         :return: Image payload
         """
         cache_key = cache_key or self.get_cache_key(window_size, thumb_size)
-        cache_payload = self.get_from_cache_key(cache_key) or 
ScreenshotCachePayload()
-        if not cache_payload.should_trigger_task(force=force):
-            logger.info(
-                "Skipping compute - already processed for thumbnail: %s", 
cache_key
-            )
-            return
-
-        window_size = window_size or self.window_size
-        thumb_size = thumb_size or self.thumb_size
-        logger.info("Processing url for thumbnail: %s", cache_key)
-        cache_payload.computing()
-        image = None
-        # Assuming all sorts of things can go wrong with Selenium
         try:
-            logger.info("trying to generate screenshot")
-            with 
event_logger.log_context(f"screenshot.compute.{self.thumbnail_type}"):
-                image = self.get_screenshot(user=user, window_size=window_size)
-        except Exception as ex:  # pylint: disable=broad-except
-            logger.warning("Failed at generating thumbnail %s", ex, 
exc_info=True)
-            cache_payload.error()
-        if image and window_size != thumb_size:
-            try:
-                image = self.resize_image(image, thumb_size=thumb_size)
-            except Exception as ex:  # pylint: disable=broad-except
-                logger.warning("Failed at resizing thumbnail %s", ex, 
exc_info=True)
-                cache_payload.error()
+            with DistributedLock(
+                namespace="thumbnail",
+                key=cache_key,
+                ttl_seconds=app.config["THUMBNAIL_COMPUTING_CACHE_TTL"],
+            ):
+                cache_payload = (
+                    self.get_from_cache_key(cache_key) or 
ScreenshotCachePayload()
+                )
+                if not cache_payload.should_trigger_task(force=force):
+                    logger.info(
+                        "Skipping compute - already processed for thumbnail: 
%s",
+                        cache_key,
+                    )
+                    return
+
+                window_size = window_size or self.window_size
+                thumb_size = thumb_size or self.thumb_size
+                logger.info("Processing url for thumbnail: %s", cache_key)
+                cache_payload.computing()
+                self.cache.set(cache_key, cache_payload.to_dict())
                 image = None
-
-        # Cache the result (success or error) to avoid immediate retries
-        if image:
-            with 
event_logger.log_context(f"screenshot.cache.{self.thumbnail_type}"):
-                cache_payload.update(image)
-
-        logger.info("Caching thumbnail: %s", cache_key)
-        self.cache.set(cache_key, cache_payload.to_dict())
-        logger.info("Updated thumbnail cache; Status: %s", 
cache_payload.get_status())
-        return
+                # Assuming all sorts of things can go wrong with Selenium
+                try:
+                    logger.info("trying to generate screenshot")
+                    with event_logger.log_context(
+                        f"screenshot.compute.{self.thumbnail_type}"
+                    ):
+                        image = self.get_screenshot(user=user, 
window_size=window_size)
+                except Exception as ex:  # pylint: disable=broad-except
+                    logger.warning(
+                        "Failed at generating thumbnail %s", ex, exc_info=True
+                    )
+                    cache_payload.error()
+                if image and window_size != thumb_size:
+                    try:
+                        image = self.resize_image(image, thumb_size=thumb_size)
+                    except Exception as ex:  # pylint: disable=broad-except
+                        logger.warning(
+                            "Failed at resizing thumbnail %s", ex, 
exc_info=True
+                        )
+                        cache_payload.error()
+                        image = None
+
+                if image:
+                    with event_logger.log_context(
+                        f"screenshot.cache.{self.thumbnail_type}"
+                    ):
+                        cache_payload.update(image)
+
+                logger.info("Caching thumbnail: %s", cache_key)
+                self.cache.set(cache_key, cache_payload.to_dict())
+                logger.info(
+                    "Updated thumbnail cache; Status: %s", 
cache_payload.get_status()
+                )
+        except AcquireDistributedLockFailedException:
+            logger.info(
+                "Skipping duplicate thumbnail task for %s - lock already held",
+                cache_key,
+            )

Review Comment:
   Good catch — the finding is correct. Added  as a subclass of :
   
   - : raises  for the NX contention case;  for  (infrastructure failure)
   - : new  raises  on  (unique-constraint = lock held) and  for other 
DB/encode errors
   - : now catches only  so infrastructure failures propagate and trigger 
Celery retry
   - Test updated to use  in the side_effect
   
   Existing callers that catch the base  continue to work unchanged (subclass).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to