From 4b30e87bd5897680889ee1e443fae77fe654ffb2 Mon Sep 17 00:00:00 2001 From: Ian-Nara Date: Mon, 15 Dec 2025 22:53:20 -0700 Subject: [PATCH 1/4] add upload only option to OptOutCloudSync --- .../uid2/shared/optout/OptOutCloudSync.java | 24 ++++++++++++++++ .../uid2/shared/vertx/CloudSyncVerticle.java | 28 ++++++++++++++----- .../com/uid2/shared/vertx/ICloudSync.java | 9 ++++++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/uid2/shared/optout/OptOutCloudSync.java b/src/main/java/com/uid2/shared/optout/OptOutCloudSync.java index d97153ec..4aa7f118 100644 --- a/src/main/java/com/uid2/shared/optout/OptOutCloudSync.java +++ b/src/main/java/com/uid2/shared/optout/OptOutCloudSync.java @@ -27,6 +27,7 @@ public class OptOutCloudSync implements ICloudSync { private static final Logger LOGGER = LoggerFactory.getLogger(OptOutCloudSync.class); private final boolean fullSync; + private final boolean uploadOnly; private final String cloudFolder; private final String deltaConsumerDir; private final String partitionConsumerDir; @@ -48,7 +49,12 @@ public class OptOutCloudSync implements ICloudSync { private AtomicReference>>> handlersNewCloudPaths = new AtomicReference<>(new ArrayList<>()); public OptOutCloudSync(JsonObject jsonConfig, boolean fullSync) { + this(jsonConfig, fullSync, false); + } + + public OptOutCloudSync(JsonObject jsonConfig, boolean fullSync, boolean uploadOnly) { this.fullSync = fullSync; + this.uploadOnly = uploadOnly; this.cloudFolder = CloudUtils.normalizDirPath(jsonConfig.getString(Const.Config.OptOutS3FolderProp)); this.deltaConsumerDir = OptOutUtils.getDeltaConsumerDir(jsonConfig); this.partitionConsumerDir = OptOutUtils.getPartitionConsumerDir(jsonConfig); @@ -84,6 +90,19 @@ public OptOutCloudSync(JsonObject jsonConfig, boolean fullSync) { this.mkdirsBlocking(); } + /** + * Creates an upload-only OptOutCloudSync instance. + * This skips all download/refresh operations. + */ + public static OptOutCloudSync createUploadOnly(JsonObject jsonConfig, boolean fullSync) { + return new OptOutCloudSync(jsonConfig, fullSync, true); + } + + @Override + public boolean isUploadOnly() { + return this.uploadOnly; + } + @Override public String toCloudPath(String path) { if (OptOutUtils.isDeltaFile(path)) { @@ -121,6 +140,11 @@ public String toLocalPath(String path) { @Override public boolean refresh(Instant now, ICloudStorage fsCloud, ICloudStorage fsLocal, Consumer> handleDownloads, Consumer> handleDeletes) throws CloudStorageException { + // In upload-only mode, skip all download/sync operations + if (uploadOnly) { + return true; + } + // list local cached paths List cachedPathList = new ArrayList<>(); localListFiles(fsLocal, this.deltaConsumerDir, OptOutUtils.prefixDeltaFile, cachedPathList); diff --git a/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java b/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java index a06f4213..8cdd1dd2 100644 --- a/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java +++ b/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java @@ -167,19 +167,29 @@ public void start(Promise promise) { this.uploadExecutor = vertx.createSharedWorkerExecutor("cloudsync-" + name + "-upload-pool", this.uploadThreads); - // handle refresh event - vertx.eventBus().consumer( - eventRefresh, - o -> this.handleRefresh(o)); + // handle refresh event (skip if upload-only) + if (!cloudSync.isUploadOnly()) { + vertx.eventBus().consumer( + eventRefresh, + o -> this.handleRefresh(o)); + } else { + LOGGER.info("CloudSyncVerticle." + name + " is upload-only, skipping refresh event handler registration"); + } // upload to cloud vertx.eventBus().consumer( this.eventUpload, msg -> this.handleUpload(msg)); - cloudRefresh() - .onFailure(t -> LOGGER.error("cloudRefresh failed: " + t.getMessage(), new Exception(t))) - .onComplete(ar -> promise.handle(ar)); + // Initial refresh (skip if upload-only) + if (!cloudSync.isUploadOnly()) { + cloudRefresh() + .onFailure(t -> LOGGER.error("cloudRefresh failed: " + t.getMessage(), new Exception(t))) + .onComplete(ar -> promise.handle(ar)); + } else { + LOGGER.info("CloudSyncVerticle." + name + " is upload-only, skipping initial refresh"); + promise.complete(); + } promise.future() .onSuccess(v -> { @@ -214,6 +224,10 @@ public String eventDownloaded() { } private void handleRefresh(Message m) { + if (cloudSync.isUploadOnly()) { + LOGGER.warn("handleRefresh called but this is upload-only mode"); + return; + } cloudRefresh() .onSuccess(t -> this.storeRefreshIsFailing.set(0)) .onFailure(t -> { diff --git a/src/main/java/com/uid2/shared/vertx/ICloudSync.java b/src/main/java/com/uid2/shared/vertx/ICloudSync.java index 05997255..8f11f70f 100644 --- a/src/main/java/com/uid2/shared/vertx/ICloudSync.java +++ b/src/main/java/com/uid2/shared/vertx/ICloudSync.java @@ -15,4 +15,13 @@ public interface ICloudSync { boolean refresh(Instant now, ICloudStorage fsCloud, ICloudStorage fsLocal, Consumer> handleDownloads, Consumer> handleDeletes) throws CloudStorageException; + + /** + * Returns true if this CloudSync instance only supports upload operations. + * When true, download/refresh operations will be skipped. + * Default is false for backward compatibility. + */ + default boolean isUploadOnly() { + return false; + } } From 5be2020cd495de9aab55616c84f749f5dcd94ce8 Mon Sep 17 00:00:00 2001 From: Ian-Nara Date: Mon, 15 Dec 2025 22:54:31 -0700 Subject: [PATCH 2/4] update comment --- src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java b/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java index 8cdd1dd2..2004d082 100644 --- a/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java +++ b/src/main/java/com/uid2/shared/vertx/CloudSyncVerticle.java @@ -181,7 +181,7 @@ public void start(Promise promise) { this.eventUpload, msg -> this.handleUpload(msg)); - // Initial refresh (skip if upload-only) + // initial refresh (skip if upload-only) if (!cloudSync.isUploadOnly()) { cloudRefresh() .onFailure(t -> LOGGER.error("cloudRefresh failed: " + t.getMessage(), new Exception(t))) From af4b461e0c67fc50918047b789c4618a5e3ce370 Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Tue, 16 Dec 2025 06:00:24 +0000 Subject: [PATCH 3/4] [CI Pipeline] Released Snapshot version: 11.1.125-alpha-328-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 09a5b6bf..410c8db4 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.uid2 uid2-shared - 11.1.124 + 11.1.125-alpha-328-SNAPSHOT ${project.groupId}:${project.artifactId} Library for all the shared uid2 operations https://github.com/IABTechLab/uid2docs From 1efff0182baab5456c1cf8540758856bf7b468d3 Mon Sep 17 00:00:00 2001 From: Ian Nara <135270994+Ian-Nara@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:10:27 -0700 Subject: [PATCH 4/4] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 410c8db4..09a5b6bf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.uid2 uid2-shared - 11.1.125-alpha-328-SNAPSHOT + 11.1.124 ${project.groupId}:${project.artifactId} Library for all the shared uid2 operations https://github.com/IABTechLab/uid2docs