Skip to content

Commit cd3ae1f

Browse files
authored
feat: [PPT-1758] Added build service monitor functionality (#413)
* feat: [PPT-1758] Added build service monitor functionality * chore: removed focus from spec
1 parent a7fb4d3 commit cd3ae1f

3 files changed

Lines changed: 329 additions & 0 deletions

File tree

OPENAPI_DOC.yml

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4464,6 +4464,151 @@ paths:
44644464
application/json:
44654465
schema:
44664466
$ref: '#/components/schemas/PlaceOS__Api__Application__ContentError'
4467+
/api/engine/v2/build/monitor:
4468+
get:
4469+
tags:
4470+
- BuildMonitor
4471+
operationId: PlaceOS::Api::BuildMonitor_monitor
4472+
parameters:
4473+
- name: state
4474+
in: query
4475+
description: state of job to return. One of [pending,running,cancelled error,done].
4476+
Defaults to 'pending'
4477+
example: pending
4478+
schema:
4479+
type: string
4480+
enum:
4481+
- pending
4482+
- running
4483+
- cancelled
4484+
- error
4485+
- done
4486+
responses:
4487+
200:
4488+
description: OK
4489+
content:
4490+
application/json:
4491+
schema:
4492+
$ref: '#/components/schemas/_Array_PlaceOS__Api__BuildMonitor__TaskStatus____String_'
4493+
409:
4494+
description: Conflict
4495+
content:
4496+
application/json:
4497+
schema:
4498+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4499+
401:
4500+
description: Unauthorized
4501+
content:
4502+
application/json:
4503+
schema:
4504+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4505+
403:
4506+
description: Forbidden
4507+
404:
4508+
description: Not Found
4509+
content:
4510+
application/json:
4511+
schema:
4512+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4513+
408:
4514+
description: Request Timeout
4515+
content:
4516+
application/json:
4517+
schema:
4518+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4519+
400:
4520+
description: Bad Request
4521+
content:
4522+
application/json:
4523+
schema:
4524+
$ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError'
4525+
422:
4526+
description: Unprocessable Entity
4527+
content:
4528+
application/json:
4529+
schema:
4530+
$ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError'
4531+
406:
4532+
description: Not Acceptable
4533+
content:
4534+
application/json:
4535+
schema:
4536+
$ref: '#/components/schemas/PlaceOS__Api__Application__ContentError'
4537+
415:
4538+
description: Unsupported Media Type
4539+
content:
4540+
application/json:
4541+
schema:
4542+
$ref: '#/components/schemas/PlaceOS__Api__Application__ContentError'
4543+
/api/engine/v2/build/cancel/{job}:
4544+
delete:
4545+
tags:
4546+
- BuildMonitor
4547+
operationId: PlaceOS::Api::BuildMonitor_cancel
4548+
parameters:
4549+
- name: job
4550+
in: path
4551+
description: ID of previously submitted compilation job
4552+
required: true
4553+
schema:
4554+
type: string
4555+
responses:
4556+
200:
4557+
description: OK
4558+
content:
4559+
application/json:
4560+
schema:
4561+
$ref: '#/components/schemas/PlaceOS__Api__BuildMonitor__CancelStatus'
4562+
409:
4563+
description: Conflict
4564+
content:
4565+
application/json:
4566+
schema:
4567+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4568+
401:
4569+
description: Unauthorized
4570+
content:
4571+
application/json:
4572+
schema:
4573+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4574+
403:
4575+
description: Forbidden
4576+
404:
4577+
description: Not Found
4578+
content:
4579+
application/json:
4580+
schema:
4581+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4582+
408:
4583+
description: Request Timeout
4584+
content:
4585+
application/json:
4586+
schema:
4587+
$ref: '#/components/schemas/PlaceOS__Api__Application__CommonError'
4588+
400:
4589+
description: Bad Request
4590+
content:
4591+
application/json:
4592+
schema:
4593+
$ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError'
4594+
422:
4595+
description: Unprocessable Entity
4596+
content:
4597+
application/json:
4598+
schema:
4599+
$ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError'
4600+
406:
4601+
description: Not Acceptable
4602+
content:
4603+
application/json:
4604+
schema:
4605+
$ref: '#/components/schemas/PlaceOS__Api__Application__ContentError'
4606+
415:
4607+
description: Unsupported Media Type
4608+
content:
4609+
application/json:
4610+
schema:
4611+
$ref: '#/components/schemas/PlaceOS__Api__Application__ContentError'
44674612
/api/engine/v2/chatgpt:
44684613
get:
44694614
summary: list user chats
@@ -22116,6 +22261,55 @@ components:
2211622261
id:
2211722262
type: string
2211822263
nullable: true
22264+
_Array_PlaceOS__Api__BuildMonitor__TaskStatus____String_:
22265+
anyOf:
22266+
- type: array
22267+
items:
22268+
type: object
22269+
properties:
22270+
state:
22271+
type: string
22272+
enum:
22273+
- pending
22274+
- running
22275+
- cancelled
22276+
- error
22277+
- done
22278+
id:
22279+
type: string
22280+
message:
22281+
type: string
22282+
driver:
22283+
type: string
22284+
repo:
22285+
type: string
22286+
branch:
22287+
type: string
22288+
commit:
22289+
type: string
22290+
timestamp:
22291+
type: string
22292+
format: date-time
22293+
required:
22294+
- state
22295+
- id
22296+
- message
22297+
- driver
22298+
- repo
22299+
- branch
22300+
- commit
22301+
- timestamp
22302+
- type: string
22303+
PlaceOS__Api__BuildMonitor__CancelStatus:
22304+
type: object
22305+
properties:
22306+
status:
22307+
type: string
22308+
message:
22309+
type: string
22310+
required:
22311+
- status
22312+
- message
2211922313
PlaceOS__Model__Chat:
2212022314
type: object
2212122315
properties:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
require "../helper"
2+
3+
module PlaceOS::Api
4+
describe "BuildMonitor" do
5+
describe "GET /" do
6+
it "responds to monitor request" do
7+
path = "#{BuildMonitor.base_route}monitor"
8+
result = client.get(path, headers: Spec::Authentication.headers)
9+
result.status_code.should eq 200
10+
end
11+
it "responds to cancel job" do
12+
path = "#{BuildMonitor.base_route}cancel/uknown_job"
13+
result = client.get(path, headers: Spec::Authentication.headers)
14+
result.status_code.should eq 404
15+
end
16+
end
17+
end
18+
end
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
require "placeos-core-client"
2+
require "placeos-driver/proxy/system"
3+
4+
require "./application"
5+
6+
module PlaceOS::Api
7+
class BuildMonitor < Application
8+
base "/api/engine/v2/build/"
9+
10+
# Scopes
11+
###############################################################################################
12+
13+
before_action :can_read, only: [:monitor]
14+
before_action :can_write, only: [:cancel]
15+
16+
before_action :check_admin, only: [:cancel]
17+
18+
###############################################################################################
19+
20+
@[AC::Route::GET("/monitor")]
21+
def monitor(
22+
@[AC::Param::Info(name: "state", description: "state of job to return. One of [pending,running,cancelled error,done]. Defaults to 'pending'", example: "pending")]
23+
state : PlaceOS::Core::Client::State = PlaceOS::Core::Client::State::Pending,
24+
) : Array(TaskStatus) | String
25+
code, result = self.class.monitor_jobs(state, request_id)
26+
if code < 500
27+
render status: code, json: Array(TaskStatus).from_json(result)
28+
else
29+
render status: code, text: result
30+
end
31+
end
32+
33+
@[AC::Route::DELETE("/cancel/:job")]
34+
def cancel(
35+
@[AC::Param::Info(name: "job", description: "ID of previously submitted compilation job")]
36+
job : String,
37+
) : CancelStatus
38+
code, result = self.class.cancel_job(job, request_id)
39+
render status: code, json: CancelStatus.from_json(result)
40+
end
41+
42+
def self.monitor_jobs(state : PlaceOS::Core::Client::State, request_id : String)
43+
details = RemoteDriver.default_discovery.node_hash
44+
45+
promises = details.map do |core_id, uri|
46+
Promise.defer {
47+
core_for(uri, request_id) do |core_client|
48+
core_client.monitor_jobs(state)
49+
end
50+
}.catch { |error|
51+
Log.error(exception: error) { {
52+
message: "failure to request a build service job status",
53+
core_uri: uri.to_s,
54+
core_id: core_id,
55+
state: state.to_s,
56+
} }
57+
{500, error.message || "failure to request a build service job status"}
58+
}
59+
end
60+
61+
Promise.race(promises).get
62+
end
63+
64+
def self.cancel_job(job : String, request_id : String)
65+
details = RemoteDriver.default_discovery.node_hash
66+
67+
promises = details.map do |core_id, uri|
68+
Promise.defer {
69+
core_for(uri, request_id) do |core_client|
70+
core_client.cancel_job(job)
71+
end
72+
}.catch { |error|
73+
Log.error(exception: error) { {
74+
message: "failure to request a cancellation of build service job",
75+
core_uri: uri.to_s,
76+
core_id: core_id,
77+
job: job,
78+
} }
79+
{500, {status: "error", message: error.message || "failure to request a cancellation of build service job"}.to_json}
80+
}
81+
end
82+
83+
Promise.race(promises).get
84+
end
85+
86+
def self.core_for(uri, request_id : String? = nil, & : Core::Client -> V) forall V
87+
Core::Client.client(uri: uri, request_id: request_id) do |client|
88+
yield client
89+
end
90+
end
91+
92+
enum State
93+
Pending
94+
Running
95+
Cancelled
96+
Error
97+
Done
98+
99+
def to_s(io : IO) : Nil
100+
io << (member_name || value.to_s).downcase
101+
end
102+
103+
def to_s : String
104+
String.build { |io| to_s(io) }
105+
end
106+
end
107+
108+
record TaskStatus, state : State, id : String, message : String,
109+
driver : String, repo : String, branch : String, commit : String, timestamp : Time do
110+
include JSON::Serializable
111+
end
112+
113+
record CancelStatus, status : String, message : String do
114+
include JSON::Serializable
115+
end
116+
end
117+
end

0 commit comments

Comments
 (0)