From 9a1b79546851b9f9fb2db7d82c1147f889e571fc Mon Sep 17 00:00:00 2001 From: Paolo Di Tommaso Date: Thu, 26 Sep 2024 11:58:26 +0200 Subject: [PATCH 1/2] Fix build succeded & status response Signed-off-by: Paolo Di Tommaso --- .../controller/RegistryProxyController.groovy | 2 +- .../wave/service/builder/BuildResult.groovy | 16 +++---- .../service/mail/impl/MailServiceImpl.groovy | 2 +- .../persistence/WaveBuildRecord.groovy | 18 +++++--- .../persistence/WaveBuildRecordTest.groovy | 43 +++++++++++++++++++ 5 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/controller/RegistryProxyController.groovy b/src/main/groovy/io/seqera/wave/controller/RegistryProxyController.groovy index 54ba69702..ec6416537 100644 --- a/src/main/groovy/io/seqera/wave/controller/RegistryProxyController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/RegistryProxyController.groovy @@ -140,7 +140,7 @@ class RegistryProxyController { if( future ) { // wait for the build completion, then apply the usual 'handleGet0' logic future - .thenApply( (build) -> build.exitStatus==0 ? handleGet0(route, httpRequest) : badRequest(build.logs) ) + .thenApply( (build) -> build.succeeded() ? handleGet0(route, httpRequest) : badRequest(build.logs) ) } else return null diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildResult.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildResult.groovy index 7dbea3e1e..3c22a65d5 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildResult.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildResult.groovy @@ -39,15 +39,15 @@ import groovy.transform.ToString class BuildResult { final String id - final int exitStatus + final Integer exitStatus final String logs final Instant startTime final Duration duration final String digest - BuildResult(String id, int exitStatus, String content, Instant startTime, Duration duration, String digest) { + BuildResult(String id, Integer exitStatus, String logs, Instant startTime, Duration duration, String digest) { this.id = id - this.logs = content?.replaceAll("\u001B\\[[;\\d]*m", "") // strip ansi escape codes + this.logs = logs?.replaceAll("\u001B\\[[;\\d]*m", "") // strip ansi escape codes this.exitStatus = exitStatus this.startTime = startTime this.duration = duration @@ -61,7 +61,7 @@ class BuildResult { Duration getDuration() { duration } - int getExitStatus() { exitStatus } + Integer getExitStatus() { exitStatus } Instant getStartTime() { startTime } @@ -75,10 +75,10 @@ class BuildResult { @Override String toString() { - return "BuildRequest[id=$id; exitStatus=$exitStatus; duration=$duration]" + return "BuildResult[id=$id; exitStatus=$exitStatus; duration=$duration]" } - static BuildResult completed(String buildId, int exitStatus, String content, Instant startTime, String digest) { + static BuildResult completed(String buildId, Integer exitStatus, String content, Instant startTime, String digest) { new BuildResult(buildId, exitStatus, content, startTime, Duration.between(startTime, Instant.now()), digest) } @@ -87,11 +87,11 @@ class BuildResult { } static BuildResult create(BuildRequest req) { - new BuildResult(req.buildId, 0, null, req.startTime, null, null) + new BuildResult(req.buildId, null, null, req.startTime, null, null) } static BuildResult create(String buildId) { - new BuildResult(buildId, 0, null, Instant.now(), null, null) + new BuildResult(buildId, null, null, Instant.now(), null, null) } @Memoized diff --git a/src/main/groovy/io/seqera/wave/service/mail/impl/MailServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/mail/impl/MailServiceImpl.groovy index 259183d25..4eea0de03 100644 --- a/src/main/groovy/io/seqera/wave/service/mail/impl/MailServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/mail/impl/MailServiceImpl.groovy @@ -88,7 +88,7 @@ class MailServiceImpl implements MailService { final status = result.succeeded() ? 'DONE': 'FAILED' binding.build_id = result.id binding.build_user = "${req.identity?.user ? req.identity.user.userName : '-'} (${req.ip})" - binding.build_success = result.exitStatus==0 + binding.build_success = result.succeeded() binding.build_exit_status = result.exitStatus binding.build_time = formatTimestamp(result.startTime, req.offsetId) ?: '-' binding.build_duration = formatDuration(result.duration) ?: '-' diff --git a/src/main/groovy/io/seqera/wave/service/persistence/WaveBuildRecord.groovy b/src/main/groovy/io/seqera/wave/service/persistence/WaveBuildRecord.groovy index ba5225b34..f5f7c4d5b 100644 --- a/src/main/groovy/io/seqera/wave/service/persistence/WaveBuildRecord.groovy +++ b/src/main/groovy/io/seqera/wave/service/persistence/WaveBuildRecord.groovy @@ -24,17 +24,21 @@ import java.time.Instant import groovy.transform.CompileStatic import groovy.transform.EqualsAndHashCode import groovy.transform.ToString +import io.seqera.wave.api.BuildStatusResponse +import io.seqera.wave.service.builder.BuildEntry import io.seqera.wave.service.builder.BuildEvent import io.seqera.wave.service.builder.BuildFormat import io.seqera.wave.api.BuildStatusResponse +import io.seqera.wave.service.builder.BuildRequest +import io.seqera.wave.service.builder.BuildResult /** * A collection of request and response properties to be stored * * @author : jorge * */ -@ToString +@ToString(includePackage = false, includeNames = true) @CompileStatic @EqualsAndHashCode class WaveBuildRecord { @@ -56,7 +60,9 @@ class WaveBuildRecord { BuildFormat format String digest - boolean succeeded() { exitStatus==0 } + Boolean succeeded() { + return duration != null ? (exitStatus==0) : null + } static WaveBuildRecord fromEvent(BuildEvent event) { if( event.result && event.request.buildId != event.result.id ) @@ -82,18 +88,16 @@ class WaveBuildRecord { } BuildStatusResponse toStatusResponse() { - final status = exitStatus != null + final status = duration!=null ? BuildStatusResponse.Status.COMPLETED : BuildStatusResponse.Status.PENDING - final succeeded = exitStatus!=null - ? exitStatus==0 - : null + return new BuildStatusResponse( buildId, status, startTime, duration, - succeeded ) + succeeded() ) } } diff --git a/src/test/groovy/io/seqera/wave/service/persistence/WaveBuildRecordTest.groovy b/src/test/groovy/io/seqera/wave/service/persistence/WaveBuildRecordTest.groovy index 75ebd6c8c..6b4fef59a 100644 --- a/src/test/groovy/io/seqera/wave/service/persistence/WaveBuildRecordTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/persistence/WaveBuildRecordTest.groovy @@ -19,6 +19,7 @@ package io.seqera.wave.service.persistence import spock.lang.Specification +import spock.lang.Unroll import java.nio.file.Path import java.time.Duration @@ -124,4 +125,46 @@ class WaveBuildRecordTest extends Specification { } + @Unroll + def 'should validate status and succeeded' () { + given: + final request = new BuildRequest( + 'container1234', + 'FROM foo:latest', + 'conda::recipe', + Path.of("/some/path"), + 'docker.io/my/repo:container1234', + PlatformId.NULL, + ContainerPlatform.of('amd64'), + 'docker.io/my/cache', + '1.2.3.4', + '{"config":"json"}', + null, + null, + 'scan12345', + null, + BuildFormat.DOCKER, + Duration.ofMinutes(1) + ).withBuildId('123') + + final result = new BuildResult(request.buildId, EXIT, "ok", Instant.now(), DURATION, null) + final event = new BuildEvent(request, result) + + when: + final build = WaveBuildRecord.fromEvent(event) + then: + build.succeeded() == EXPECET_SUCCEED + + when: + def resp = build.toStatusResponse() + then: + resp.succeeded == EXPECET_SUCCEED + resp.status == EXPECT_STATUS + where: + EXIT | DURATION | EXPECET_SUCCEED | EXPECT_STATUS + null | null | null | BuildStatusResponse.Status.PENDING + 0 | null | null | BuildStatusResponse.Status.PENDING + 1 | Duration.ofSeconds(1) | false | BuildStatusResponse.Status.COMPLETED + 0 | Duration.ofSeconds(1) | true | BuildStatusResponse.Status.COMPLETED + } } From 42c3f260bdf5dc37eed88e91b04a074e4f85bb05 Mon Sep 17 00:00:00 2001 From: Paolo Di Tommaso Date: Thu, 26 Sep 2024 12:05:39 +0200 Subject: [PATCH 2/2] Simulate xclaim delay with local stream Signed-off-by: Paolo Di Tommaso --- .../wave/service/data/stream/impl/LocalMessageStream.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/groovy/io/seqera/wave/service/data/stream/impl/LocalMessageStream.groovy b/src/main/groovy/io/seqera/wave/service/data/stream/impl/LocalMessageStream.groovy index ce3c349be..c1d5d2dc1 100644 --- a/src/main/groovy/io/seqera/wave/service/data/stream/impl/LocalMessageStream.groovy +++ b/src/main/groovy/io/seqera/wave/service/data/stream/impl/LocalMessageStream.groovy @@ -72,7 +72,9 @@ class LocalMessageStream implements MessageStream { } finally { if( !result ) { - offer(streamId, message) + // add again message not consumed to mimic the behavior or redis stream + sleep(1_000) + offer(streamId,message) } return result }