From 7c33bbdae576aca8558a7e96b83dcb3fce5562f9 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Wed, 11 Dec 2024 14:54:04 +0700 Subject: [PATCH 1/3] feat: add basic healthcheck endpoint --- java/app/src/main/java/org/vss/KVStore.java | 2 + .../main/java/org/vss/api/HealthCheckApi.java | 45 +++++++++++++++++++ .../main/java/org/vss/api/VssApiEndpoint.java | 1 + .../impl/postgres/PostgresBackendImpl.java | 14 ++++++ 4 files changed, 62 insertions(+) create mode 100644 java/app/src/main/java/org/vss/api/HealthCheckApi.java diff --git a/java/app/src/main/java/org/vss/KVStore.java b/java/app/src/main/java/org/vss/KVStore.java index ea09991..e4ed960 100644 --- a/java/app/src/main/java/org/vss/KVStore.java +++ b/java/app/src/main/java/org/vss/KVStore.java @@ -11,4 +11,6 @@ public interface KVStore { DeleteObjectResponse delete(String userToken, DeleteObjectRequest request); ListKeyVersionsResponse listKeyVersions(String userToken, ListKeyVersionsRequest request); + + void checkHealth(); } diff --git a/java/app/src/main/java/org/vss/api/HealthCheckApi.java b/java/app/src/main/java/org/vss/api/HealthCheckApi.java new file mode 100644 index 0000000..6b29116 --- /dev/null +++ b/java/app/src/main/java/org/vss/api/HealthCheckApi.java @@ -0,0 +1,45 @@ +package org.vss.api; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import lombok.extern.slf4j.Slf4j; +import org.vss.GetObjectRequest; +import org.vss.GetObjectResponse; +import org.vss.KVStore; +import org.vss.auth.AuthResponse; +import org.vss.auth.Authorizer; + +@Path(VssApiEndpoint.HEALTHCHECK) +@Slf4j +public class HealthCheckApi { + KVStore kvStore; + + @Inject + public HealthCheckApi(KVStore kvstore) { + this.kvStore = kvstore; + } + + @GET + public Response execute(@Context HttpHeaders headers) { + try { + log.info("Healthcheck requested"); + kvStore.checkHealth(); + log.info("Healthcheck passed"); + + return Response + .status(Response.Status.OK) + .build(); + } catch (Exception e) { + log.error("Exception in HealthCheckApi: ", e); + return Response.status(500) + .entity("an unexpected error occurred: " + e.getMessage()) + .build(); + } + } +} diff --git a/java/app/src/main/java/org/vss/api/VssApiEndpoint.java b/java/app/src/main/java/org/vss/api/VssApiEndpoint.java index 983bc27..b4171a7 100644 --- a/java/app/src/main/java/org/vss/api/VssApiEndpoint.java +++ b/java/app/src/main/java/org/vss/api/VssApiEndpoint.java @@ -1,6 +1,7 @@ package org.vss.api; public class VssApiEndpoint { + public static final String HEALTHCHECK = "/health"; public static final String GET_OBJECT = "/getObject"; public static final String PUT_OBJECTS = "/putObjects"; public static final String DELETE_OBJECT = "/deleteObject"; diff --git a/java/app/src/main/java/org/vss/impl/postgres/PostgresBackendImpl.java b/java/app/src/main/java/org/vss/impl/postgres/PostgresBackendImpl.java index c9330d8..749c610 100644 --- a/java/app/src/main/java/org/vss/impl/postgres/PostgresBackendImpl.java +++ b/java/app/src/main/java/org/vss/impl/postgres/PostgresBackendImpl.java @@ -47,6 +47,20 @@ public PostgresBackendImpl(DSLContext context) { this.context = context; } + @Override + public void checkHealth() { + OffsetDateTime yesterday = OffsetDateTime.now().minusDays(1); + + VssDbRecord vssDbRecord = context.selectFrom(VSS_DB) + .where(VSS_DB.LAST_UPDATED_AT.gt(yesterday)) + .limit(1) + .fetchOne(); + + if (vssDbRecord == null) { + throw new IllegalStateException("No recent records found"); + } + } + @Override public GetObjectResponse get(String userToken, GetObjectRequest request) { From 7e1dd17331f5fdf42ea118ca6ad6796877aa1721 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Wed, 11 Dec 2024 17:18:31 +0700 Subject: [PATCH 2/3] feat: add sentry --- java/app/build.gradle | 12 ++++++++++++ .../src/main/java/org/vss/api/DeleteObjectApi.java | 2 ++ java/app/src/main/java/org/vss/api/GetObjectApi.java | 2 ++ .../src/main/java/org/vss/api/HealthCheckApi.java | 2 ++ .../main/java/org/vss/api/ListKeyVersionsApi.java | 2 ++ .../app/src/main/java/org/vss/api/PutObjectsApi.java | 2 ++ java/app/src/main/java/org/vss/guice/BaseModule.java | 6 ++++++ 7 files changed, 28 insertions(+) diff --git a/java/app/build.gradle b/java/app/build.gradle index e55f506..98f3a74 100644 --- a/java/app/build.gradle +++ b/java/app/build.gradle @@ -15,6 +15,7 @@ plugins { id 'war' id 'idea' id 'nu.studer.jooq' version '8.0' + id "io.sentry.jvm.gradle" version "4.14.1" } repositories { @@ -34,6 +35,17 @@ sourceSets { } } +sentry { + // Generates a JVM (Java, Kotlin, etc.) source bundle and uploads your source code to Sentry. + // This enables source context, allowing you to see your source + // code as part of your stack traces in Sentry. + includeSourceContext = true + + org = "getalby" + projectName = "albyhub-vss" + authToken = System.getenv("SENTRY_AUTH_TOKEN") +} + group 'org.vss' version '1.0' diff --git a/java/app/src/main/java/org/vss/api/DeleteObjectApi.java b/java/app/src/main/java/org/vss/api/DeleteObjectApi.java index c803a90..eb56b9e 100644 --- a/java/app/src/main/java/org/vss/api/DeleteObjectApi.java +++ b/java/app/src/main/java/org/vss/api/DeleteObjectApi.java @@ -14,6 +14,7 @@ import org.vss.KVStore; import org.vss.auth.AuthResponse; import org.vss.auth.Authorizer; +import io.sentry.Sentry; @Path(VssApiEndpoint.DELETE_OBJECT) @Slf4j @@ -33,6 +34,7 @@ public Response execute(byte[] payload, @Context HttpHeaders headers) { return toResponse(response); } catch (Exception e) { log.error("Exception in DeleteObjectApi: ", e); + Sentry.captureException(e); return toErrorResponse(e); } } diff --git a/java/app/src/main/java/org/vss/api/GetObjectApi.java b/java/app/src/main/java/org/vss/api/GetObjectApi.java index cdc5bdd..626869b 100644 --- a/java/app/src/main/java/org/vss/api/GetObjectApi.java +++ b/java/app/src/main/java/org/vss/api/GetObjectApi.java @@ -14,6 +14,7 @@ import org.vss.KVStore; import org.vss.auth.AuthResponse; import org.vss.auth.Authorizer; +import io.sentry.Sentry; @Path(VssApiEndpoint.GET_OBJECT) @Slf4j @@ -34,6 +35,7 @@ public Response execute(byte[] payload, @Context HttpHeaders headers) { return toResponse(response); } catch (Exception e) { log.error("Exception in GetObjectApi: ", e); + Sentry.captureException(e); return toErrorResponse(e); } } diff --git a/java/app/src/main/java/org/vss/api/HealthCheckApi.java b/java/app/src/main/java/org/vss/api/HealthCheckApi.java index 6b29116..3a3194a 100644 --- a/java/app/src/main/java/org/vss/api/HealthCheckApi.java +++ b/java/app/src/main/java/org/vss/api/HealthCheckApi.java @@ -14,6 +14,7 @@ import org.vss.KVStore; import org.vss.auth.AuthResponse; import org.vss.auth.Authorizer; +import io.sentry.Sentry; @Path(VssApiEndpoint.HEALTHCHECK) @Slf4j @@ -37,6 +38,7 @@ public Response execute(@Context HttpHeaders headers) { .build(); } catch (Exception e) { log.error("Exception in HealthCheckApi: ", e); + Sentry.captureException(e); return Response.status(500) .entity("an unexpected error occurred: " + e.getMessage()) .build(); diff --git a/java/app/src/main/java/org/vss/api/ListKeyVersionsApi.java b/java/app/src/main/java/org/vss/api/ListKeyVersionsApi.java index 3ac8ba7..02dbe6d 100644 --- a/java/app/src/main/java/org/vss/api/ListKeyVersionsApi.java +++ b/java/app/src/main/java/org/vss/api/ListKeyVersionsApi.java @@ -14,6 +14,7 @@ import org.vss.ListKeyVersionsResponse; import org.vss.auth.AuthResponse; import org.vss.auth.Authorizer; +import io.sentry.Sentry; @Path(VssApiEndpoint.LIST_KEY_VERSIONS) @Slf4j @@ -34,6 +35,7 @@ public Response execute(byte[] payload, @Context HttpHeaders headers) { return toResponse(response); } catch (Exception e) { log.error("Exception in ListKeyVersionsApi: ", e); + Sentry.captureException(e); return toErrorResponse(e); } } diff --git a/java/app/src/main/java/org/vss/api/PutObjectsApi.java b/java/app/src/main/java/org/vss/api/PutObjectsApi.java index 8fedc0e..87cc189 100644 --- a/java/app/src/main/java/org/vss/api/PutObjectsApi.java +++ b/java/app/src/main/java/org/vss/api/PutObjectsApi.java @@ -14,6 +14,7 @@ import org.vss.PutObjectResponse; import org.vss.auth.AuthResponse; import org.vss.auth.Authorizer; +import io.sentry.Sentry; @Path(VssApiEndpoint.PUT_OBJECTS) @Slf4j @@ -34,6 +35,7 @@ public Response execute(byte[] payload, @Context HttpHeaders headers) { return toResponse(response); } catch (Exception e) { log.error("Exception in PutObjectsApi: ", e); + Sentry.captureException(e); return toErrorResponse(e); } } diff --git a/java/app/src/main/java/org/vss/guice/BaseModule.java b/java/app/src/main/java/org/vss/guice/BaseModule.java index 0dbc2c3..c8ba5de 100644 --- a/java/app/src/main/java/org/vss/guice/BaseModule.java +++ b/java/app/src/main/java/org/vss/guice/BaseModule.java @@ -17,11 +17,17 @@ import org.vss.auth.NoopAuthorizer; import org.vss.impl.postgres.PostgresBackendImpl; import org.vss.auth.JwtAuthorizer; +import io.sentry.Sentry; public class BaseModule extends AbstractModule { @Override protected void configure() { + Sentry.init(options -> { + options.setDsn(System.getenv("vss.sentry.dsn")); + // options.setDebug(true); + }); + // Provide PostgresBackend as default implementation for KVStore. bind(KVStore.class).to(PostgresBackendImpl.class).in(Singleton.class); From bf42dbac35d116c607a7da6cdb5dc8872b555a63 Mon Sep 17 00:00:00 2001 From: Fmar Date: Wed, 11 Dec 2024 18:18:00 +0100 Subject: [PATCH 3/3] only add sentry if there is env --- java/app/build.gradle | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/java/app/build.gradle b/java/app/build.gradle index 98f3a74..c893685 100644 --- a/java/app/build.gradle +++ b/java/app/build.gradle @@ -35,17 +35,18 @@ sourceSets { } } -sentry { - // Generates a JVM (Java, Kotlin, etc.) source bundle and uploads your source code to Sentry. - // This enables source context, allowing you to see your source - // code as part of your stack traces in Sentry. - includeSourceContext = true - - org = "getalby" - projectName = "albyhub-vss" - authToken = System.getenv("SENTRY_AUTH_TOKEN") +if(System.getenv("SENTRY_AUTH_TOKEN") != null) { + sentry { + // Generates a JVM (Java, Kotlin, etc.) source bundle and uploads your source code to Sentry. + // This enables source context, allowing you to see your source + // code as part of your stack traces in Sentry. + includeSourceContext = true + + org = "getalby" + projectName = "albyhub-vss" + authToken = System.getenv("SENTRY_AUTH_TOKEN") + } } - group 'org.vss' version '1.0'