diff --git a/Dockerfile b/Dockerfile index e7440a4..ff10050 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,5 +8,6 @@ RUN addgroup -S spring && adduser -S spring -G spring USER spring:spring EXPOSE 8080 +EXPOSE 9090 ENTRYPOINT ["java", "-jar", "app.jar"] \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 82b27ef..4ccc8b4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,11 @@ +import com.google.protobuf.gradle.* + plugins { java jacoco id("org.springframework.boot") version "4.0.1" id("io.spring.dependency-management") version "1.1.7" + id("com.google.protobuf") version "0.9.4" } group = "com.devoops" @@ -19,6 +22,8 @@ repositories { mavenCentral() } +val grpcVersion = "1.68.0" + dependencies { // Web and Core implementation("org.springframework.boot:spring-boot-starter-webmvc") @@ -40,6 +45,13 @@ dependencies { annotationProcessor("org.mapstruct:mapstruct-processor:1.6.3") annotationProcessor("org.projectlombok:lombok-mapstruct-binding:0.2.0") + // gRPC Server + implementation("net.devh:grpc-server-spring-boot-starter:3.1.0.RELEASE") + implementation("io.grpc:grpc-protobuf:$grpcVersion") + implementation("io.grpc:grpc-stub:$grpcVersion") + implementation("io.grpc:grpc-netty-shaded:$grpcVersion") + compileOnly("javax.annotation:javax.annotation-api:1.3.2") + // Prometheus implementation("io.micrometer:micrometer-registry-prometheus") @@ -64,6 +76,24 @@ dependencies { testRuntimeOnly("org.junit.platform:junit-platform-launcher") } +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.25.5" + } + plugins { + id("grpc") { + artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" + } + } + generateProtoTasks { + all().forEach { task -> + task.plugins { + id("grpc") + } + } + } +} + tasks.withType { useJUnitPlatform() finalizedBy(tasks.jacocoTestReport) diff --git a/environment/.local.env b/environment/.local.env index ba3bcc2..6b790fb 100644 --- a/environment/.local.env +++ b/environment/.local.env @@ -5,4 +5,5 @@ ZIPKIN_PORT=9411 POSTGRES_HOST=devoops-postgres POSTGRES_PORT=5432 DB_USERNAME=reservation-service -DB_PASSWORD=reservation-service-pass \ No newline at end of file +DB_PASSWORD=reservation-service-pass +GRPC_PORT=9090 \ No newline at end of file diff --git a/src/main/java/com/devoops/reservation/grpc/ReservationGrpcService.java b/src/main/java/com/devoops/reservation/grpc/ReservationGrpcService.java new file mode 100644 index 0000000..32b9e35 --- /dev/null +++ b/src/main/java/com/devoops/reservation/grpc/ReservationGrpcService.java @@ -0,0 +1,44 @@ +package com.devoops.reservation.grpc; + +import com.devoops.reservation.entity.Reservation; +import com.devoops.reservation.grpc.proto.CheckReservationsExistRequest; +import com.devoops.reservation.grpc.proto.CheckReservationsExistResponse; +import com.devoops.reservation.grpc.proto.ReservationInternalServiceGrpc; +import com.devoops.reservation.repository.ReservationRepository; +import io.grpc.stub.StreamObserver; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.devh.boot.grpc.server.service.GrpcService; + +import java.time.LocalDate; +import java.util.List; +import java.util.UUID; + +@GrpcService +@RequiredArgsConstructor +@Slf4j +public class ReservationGrpcService extends ReservationInternalServiceGrpc.ReservationInternalServiceImplBase { + + private final ReservationRepository reservationRepository; + + @Override + public void checkReservationsExist(CheckReservationsExistRequest request, + StreamObserver responseObserver) { + UUID accommodationId = UUID.fromString(request.getAccommodationId()); + LocalDate startDate = LocalDate.parse(request.getStartDate()); + LocalDate endDate = LocalDate.parse(request.getEndDate()); + + log.debug("gRPC: Checking reservations for accommodation {} between {} and {}", + accommodationId, startDate, endDate); + + List overlapping = reservationRepository.findOverlappingApproved( + accommodationId, startDate, endDate); + + CheckReservationsExistResponse response = CheckReservationsExistResponse.newBuilder() + .setHasReservations(!overlapping.isEmpty()) + .build(); + + responseObserver.onNext(response); + responseObserver.onCompleted(); + } +} diff --git a/src/main/proto/reservation_internal.proto b/src/main/proto/reservation_internal.proto new file mode 100644 index 0000000..89d4e01 --- /dev/null +++ b/src/main/proto/reservation_internal.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package reservation; + +option java_multiple_files = true; +option java_package = "com.devoops.reservation.grpc.proto"; + +service ReservationInternalService { + rpc CheckReservationsExist(CheckReservationsExistRequest) returns (CheckReservationsExistResponse); +} + +message CheckReservationsExistRequest { + string accommodation_id = 1; + string start_date = 2; + string end_date = 3; +} + +message CheckReservationsExistResponse { + bool has_reservations = 1; +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1260034..3dfb8ea 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -29,3 +29,6 @@ management.tracing.export.zipkin.endpoint=http://${ZIPKIN_HOST:zipkin}:${ZIPKIN_ management.endpoints.web.exposure.include=health,info,prometheus management.endpoint.health.show-details=always management.prometheus.metrics.export.enabled=true + +# gRPC Server +grpc.server.port=${GRPC_PORT:9090}