public <T> T underBucketLocks(Collection<String> bucketLocations, Supplier<T> function) {
        List<String> keys = bucketLocations.stream()
                .map(bucketLocation -> BlobStorageUtil.toStoragePath(prefix, bucketLocation))
                .distinct()
                .sorted()
                .toList();

        List<Lock> locks = new ArrayList<>(keys.size());

        try {
            for (String key : keys) {
                Lock lock = lock(key);
                locks.add(lock);
            }

            return function.get();
        } finally {
            for (Lock lock : locks) {
                lock.close();
            }
        }
    }
Simple spin-lock implementation which works with Redis as cache. Supports volatile-* eviction policies.
storage/src/main/java/com/epam/aidial/core/storage/service/LockService.java