Skip to content
This repository has been archived by the owner on Nov 29, 2024. It is now read-only.

Commit

Permalink
feat: 🎏 introduce /readyz endpoint probe (#463)
Browse files Browse the repository at this point in the history
* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

* feat: introduce  endpoint probe

---------

Co-authored-by: Jakub Háva <jakub.hava@h2o.ai>
  • Loading branch information
shsma and jakubhava authored Nov 27, 2024
1 parent 5d360d1 commit aa1f596
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ terraform.tfstate*

###
.DS_Store

# VSCode
.vscode/
14 changes: 14 additions & 0 deletions common/swagger/v1/jdbc-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ paths:
description: Successful operation
schema:
$ref: '#/definitions/Model'
'/readyz':
get:
tags:
- health
summary: Readiness check
description: Checks if the model schema can be retrieved successfully.
operationId: getReadyz
produces:
- application/json
responses:
'200':
description: Model is ready
'500':
description: Model not ready
'/model/score':
post:
tags:
Expand Down
15 changes: 15 additions & 0 deletions common/swagger/v1/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ paths:
description: Successful operation
schema:
$ref: '#/definitions/Model'
'/readyz':
get:
tags:
- health
summary: Readiness check
description: Checks if the model schema can be retrieved successfully.
operationId: getReadyz
produces:
- application/json
responses:
'200':
description: Model is ready
'500':
description: Model not ready

'/model/sample_request':
get:
tags:
Expand Down
32 changes: 32 additions & 0 deletions common/swagger/v1openapi3/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,38 @@
}
}
},
"/readyz": {
"get": {
"tags": [
"heath"
],
"summary": "Readiness check",
"description": "Checks if the model schema can be retrieved successfully.",
"operationId": "getReadyz",
"responses": {
"200": {
"description": "Model is ready",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
},
"500": {
"description": "Model not ready",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/model/sample_request": {
"get": {
"tags": [
Expand Down
20 changes: 20 additions & 0 deletions common/swagger/v1openapi3/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,26 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Model'
/readyz:
get:
tags:
- health
summary: Readiness check
description: Checks if the model schema can be retrieved successfully.
operationId: getReadyz
responses:
"200":
description: Model is ready
content:
application/json:
schema:
type: string
"500":
description: Model not ready
content:
application/json:
schema:
type: string
/model/sample_request:
get:
tags:
Expand Down
10 changes: 10 additions & 0 deletions local-rest-scorer/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
id 'org.springframework.boot'
id 'com.diffplug.spotless' version '6.22.0'
}

apply from: project(":").file('gradle/java.gradle')

dependencies {
Expand Down Expand Up @@ -57,3 +59,11 @@ rootProject.distributionZip {
from bootJar.archivePath
}
}

// Spotless Configuration
spotless {
java {
googleJavaFormat()
target 'src/**/*.java'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package ai.h2o.mojos.deploy.local.rest.controller;

import ai.h2o.mojos.deploy.common.rest.api.ReadyzApi;
import ai.h2o.mojos.deploy.common.rest.model.ModelSchema;
import ai.h2o.mojos.deploy.common.transform.MojoScorer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ReadyzApiController implements ReadyzApi {

private final MojoScorer scorer;
private static final Logger log = LoggerFactory.getLogger(ReadyzApiController.class);

public ReadyzApiController(MojoScorer scorer) {
this.scorer = scorer;
}

@Override
public ResponseEntity<String> getReadyz() {
try {
ModelSchema modelSchema = scorer.getModelInfo().getSchema();
log.trace("model is ready: {}", modelSchema);
return ResponseEntity.ok("Ready");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Not ready");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
logging.level.ai.h2o.mojos.deploy.common.transform.MojoScorer=${LOGLEVEL}
logging.level.ai.h2o.mojos.deploy.local.rest.controller.ModelsApiController=${LOGLEVEL}
logging.level.ai.h2o.mojos.deploy.local.rest.controller.ReadyzApiController=${LOGLEVEL}
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,14 @@
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;

@ExtendWith(MockitoExtension.class)
class ModelsApiControllerTest {
@Mock
private SampleRequestBuilder sampleRequestBuilder;
@Mock private SampleRequestBuilder sampleRequestBuilder;

@BeforeAll
static void setup() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ai.h2o.mojos.deploy.local.rest.controller;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

import ai.h2o.mojos.deploy.common.rest.model.Model;
import ai.h2o.mojos.deploy.common.rest.model.ModelSchema;
import ai.h2o.mojos.deploy.common.transform.MojoScorer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

@ExtendWith(MockitoExtension.class)
class ReadyzApiControllerTest {

@Mock private MojoScorer scorer;

@InjectMocks private ReadyzApiController controller;

@Test
void getReadyz_WhenModelSchemaSucceeds_ReturnsOk() {
Model model = new Model();
model.setSchema(new ModelSchema());
when(scorer.getModelInfo()).thenReturn(model);

ResponseEntity<String> response = controller.getReadyz();

assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("Ready", response.getBody());
}

@Test
void getReadyz_WhenModelSchemaFails_ReturnsError() {
when(scorer.getModelInfo()).thenThrow(new RuntimeException("Test error"));

ResponseEntity<String> response = controller.getReadyz();

assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
assertEquals("Not ready", response.getBody());
}
}

0 comments on commit aa1f596

Please sign in to comment.