Query reg TTL during update (suspicious ttl warning)

Hi Team,
Using couchbase create operation and by setting the expiry duration , I create the document.

Code for Create Operation

private static Cluster cluster = Cluster.connect(host, userName, password);
	private static Bucket bucket = cluster.bucket(bneOtherbucketName);
	public static void main(String[] args) {
		bucket.waitUntilReady(Duration.ofSeconds(5000));
		String documentId = "EMPLOYEE:11";
		// Code for create
		JsonObject jsonObj = JsonObject.create().put("type", "EMPLOYEE").put("name", "user11").put("age", 25);
		Duration expiryDuration = Duration.ofDays(3);
		System.out.println("Duration : " + expiryDuration + " Duration in seconds : " + expiryDuration.getSeconds());
		InsertOptions options = InsertOptions.insertOptions().expiry(expiryDuration);
		MutationResult res = bucket.defaultCollection().insert(documentId, jsonObj, options);
	}

O/p: Duration : PT72H Duration in seconds : 259200

image

Code For Update

	public static void main(String[] args) {
		bucket.waitUntilReady(Duration.ofSeconds(5000));
		String documentId = "EMPLOYEE:11";

		// Get Existing Duration
		List<LookupInSpec> specs = new ArrayList<>();
		specs.add(get("$document.exptime").xattr());
		LookupInResult lookupResult = bucket.defaultCollection().lookupIn(documentId, specs);
		Long expiry = lookupResult.contentAs(0, Long.class);
		*Duration duration = Duration.ofSeconds(expiry);*

		// Update using Duration
		List<MutateInSpec> mutateInSpecs = new ArrayList<>();
		mutateInSpecs.add(replace("age", 55));
		MutateInOptions options = MutateInOptions.mutateInOptions().expiry(duration);
		MutateInResult result = bucket.defaultCollection().mutateIn(documentId, mutateInSpecs, options);
	}

During update I need to get the existing value and update it again as expiry. since the update resets expiration. I get the below warning in code.

*WARN [cb-events] c.c.request [523] [com.couchbase.request][SuspiciousExpiryDurationEvent] The specified expiry duration PT453084H21M59S is longer than 50 years. For bug-compatibility with previous versions of SDK 3.0.x, the number of seconds in the duration will be interpreted as the epoch second when the document should expire (2021-09-08T12:21:59Z). Stuffing an epoch second into a Duration is deprecated and will no longer work in SDK 3.1.*
*java.lang.Throwable: Deprecated expiry duration usage (not a failure, just informative)*
*        at com.couchbase.client.core.cnc.events.request.SuspiciousExpiryDurationEvent.<init>(SuspiciousExpiryDurationEvent.java:42)*
*        at com.couchbase.client.java.kv.Expiry.encode(Expiry.java:70)*
*        at com.couchbase.client.java.AsyncCollection.lambda$mutateInRequest$49(AsyncCollection.java:1189)*
*        at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:981)*
*        at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2124)*
*        at com.couchbase.client.java.AsyncCollection.mutateInRequest(AsyncCollection.java:1161)*
*        at com.couchbase.client.java.AsyncCollection.mutateIn(AsyncCollection.java:1119)*
*        at com.couchbase.client.java.Collection.mutateIn(Collection.java:581)*

As per my understanding,

In Expiry.class,
the below variable is configured as shown below.

private static final int WORKAROUND_EXPIRY_CUTOFF_SECONDS = (int) DAYS.toSeconds(365) * 50;
WORKAROUND_EXPIRY_CUTOFF_SECONDS = 1576800000

The value that I get as result of lookup in is 1629546366. This is always going to be greater than WORKAROUND_EXPIRY_CUTOFF_SECONDS .

So my query is , after I get the data , to which format of duration I need to change in order to avoid the warning.


                 **Long expiry = lookupResult.contentAs(0, Long.class);**
		*Duration duration = Duration.ofSeconds(expiry);

Thanks,
Manzoor

1 Like

Hi Manzoor,

The value of $document.exptime is the epoch second when the document expires, not a duration. Try this instead:

long expiryEpochSecond = lookupResult.contentAs(0, Long.class);
Instant expiry = Instant.ofEpochSecond(expiryEpochSecond);
MutateInOptions options = MutateInOptions.mutateInOptions().expiry(expiry);

To avoid accidentally clobbering a different expiry set by a concurrent update, you could use the CAS from the LookupInResult when calling mutateIn, and start over if you get a CasMismatchException:

MutateInOptions options = MutateInOptions.mutateInOptions()
    .cas(lookupResult.cas())
    .expiry(expiry);

If you’re using Java SDK 3.1.5+ and Couchbase Server 7.0+, there’s an easier way to preserve the existing expiry:

MutateInOptions options = MutateInOptions.mutateInOptions()
    .preserveExpiry(true);

Thanks,
David