From a8e04b93eb9f81ba9bf13e2ba193070ab156e34c Mon Sep 17 00:00:00 2001 From: mchrza Date: Fri, 27 Feb 2026 13:56:23 +0100 Subject: [PATCH 1/3] DS-2036: Cancel job if client cancels connection. Signed-off-by: mchrza --- .../com/here/xyz/jobs/service/JobApi.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java b/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java index 8ae7a2f43b..ed0c6cc4c4 100644 --- a/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java +++ b/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java @@ -19,6 +19,7 @@ package com.here.xyz.jobs.service; +import static com.here.xyz.jobs.RuntimeInfo.State.CANCELLING; import static com.here.xyz.jobs.RuntimeInfo.State.FAILED; import static com.here.xyz.jobs.RuntimeInfo.State.NOT_READY; import static com.here.xyz.jobs.RuntimeInfo.State.RUNNING; @@ -47,12 +48,15 @@ import com.here.xyz.util.service.BaseHttpServerVerticle.ValidationException; import com.here.xyz.util.service.HttpException; import com.here.xyz.util.service.errors.DetailedHttpException; +import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Future; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.openapi.router.RouterBuilder; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + import org.apache.commons.lang3.NotImplementedException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -87,10 +91,27 @@ protected void postJob(final RoutingContext context) throws HttpException { protected Future createNewJob(RoutingContext context, Job job) { logger.info(getMarker(context), "Received job creation request: {}", job.serialize(true)); + AtomicBoolean clientGone = new AtomicBoolean(false); + + context.request().connection().closeHandler(v -> { + clientGone.set(true); + }); + return job.create().submit() + .compose(v -> abortIfClientGone(clientGone)) .compose(v -> applyInputReferences(job)) + .compose(v -> abortIfClientGone(clientGone)) .map(res -> job) .recover(t -> { + if(t instanceof HttpException e && e.status == HttpResponseStatus.GONE) { + logger.warn(getMarker(context), e.getMessage()); + job.getStatus() + .withState(CANCELLING) + .withErrorMessage("Client disconnected.") + .withErrorCause(t.getMessage()); + job.store(); + return Future.failedFuture(e); + } if (t instanceof CompilationError) return Future.failedFuture(new DetailedHttpException("E319002", t)); if (t instanceof ValidationException) @@ -104,6 +125,13 @@ protected Future createNewJob(RoutingContext context, Job job) { .onFailure(err -> sendErrorResponse(context, err)); } + private Future abortIfClientGone(AtomicBoolean clientGone) { + if (clientGone.get()) { + return Future.failedFuture(new HttpException(HttpResponseStatus.GONE,"Client disconnected during job creation. Aborting job.")); + } + return Future.succeededFuture(); + } + protected Future applyInputReferences(Job job) { if (job.getInputs() == null) return Future.succeededFuture(); From e3f827d130de4f81d1a9b6a84c7392c513febc2e Mon Sep 17 00:00:00 2001 From: mchrza Date: Fri, 27 Feb 2026 15:05:33 +0100 Subject: [PATCH 2/3] DS-2036: Introduce DNS_LOOKUP_TIMEOUT_SECONDS and set it to 2s Signed-off-by: mchrza --- .../main/java/com/here/xyz/util/db/DBClusterResolver.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xyz-util/src/main/java/com/here/xyz/util/db/DBClusterResolver.java b/xyz-util/src/main/java/com/here/xyz/util/db/DBClusterResolver.java index 22ac4b158e..ffd51ffa40 100644 --- a/xyz-util/src/main/java/com/here/xyz/util/db/DBClusterResolver.java +++ b/xyz-util/src/main/java/com/here/xyz/util/db/DBClusterResolver.java @@ -19,6 +19,8 @@ package com.here.xyz.util.db; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -28,9 +30,11 @@ import org.xbill.DNS.Lookup; import org.xbill.DNS.Record; import org.xbill.DNS.Name; +import org.xbill.DNS.SimpleResolver; public class DBClusterResolver { private static final Pattern RDS_CLUSTER_HOSTNAME_PATTERN = Pattern.compile("(.+).cluster-.*.rds.amazonaws.com.*"); + private static final int DNS_LOOKUP_TIMEOUT_SECONDS = 2; public static String getClusterIdFromHostname(String hostname) { if(hostname == null) return null; @@ -44,7 +48,10 @@ private static String extractClusterId(String url) { private static String resolveAndExtractClusterId(String hostname) { try { + SimpleResolver resolver = new SimpleResolver(); + resolver.setTimeout(Duration.of(DNS_LOOKUP_TIMEOUT_SECONDS, ChronoUnit.SECONDS)); Lookup lookup = new Lookup(hostname); + lookup.setResolver(resolver); List records = Arrays.stream(lookup.run()).map(Record::toString).collect(Collectors.toList()); records.addAll(Arrays.stream(lookup.getAliases()).map(Name::toString).collect(Collectors.toList())); From de728af6afaa7a8244895e32cad862d6ce5dc7a9 Mon Sep 17 00:00:00 2001 From: mchrza Date: Fri, 27 Feb 2026 15:35:50 +0100 Subject: [PATCH 3/3] DS-2036: changes based on review. Signed-off-by: mchrza --- .../src/main/java/com/here/xyz/jobs/service/JobApi.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java b/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java index ed0c6cc4c4..3d8838b867 100644 --- a/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java +++ b/xyz-jobs/xyz-job-service/src/main/java/com/here/xyz/jobs/service/JobApi.java @@ -107,9 +107,9 @@ protected Future createNewJob(RoutingContext context, Job job) { logger.warn(getMarker(context), e.getMessage()); job.getStatus() .withState(CANCELLING) - .withErrorMessage("Client disconnected.") + .withErrorMessage("Client disconnected during job submission.") .withErrorCause(t.getMessage()); - job.store(); + job.storeStatus(null); return Future.failedFuture(e); } if (t instanceof CompilationError)