Skip to content

Commit c08250d

Browse files
authored
Merge pull request #869 from Dstack-TEE/codex/fix-gateway-exit-response-order
fix(gateway): support graceful and forced exit
2 parents d78ba0f + 9207748 commit c08250d

4 files changed

Lines changed: 34 additions & 10 deletions

File tree

dstack/gateway/rpc/proto/gateway_rpc.proto

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,13 +394,18 @@ message GetNodeStatusesResponse {
394394
repeated NodeStatusEntry statuses = 1;
395395
}
396396

397+
message ExitRequest {
398+
// Exit immediately without waiting for in-flight requests to drain.
399+
bool force = 1;
400+
}
401+
397402
service Admin {
398403
// Get the status of the gateway.
399404
rpc Status(google.protobuf.Empty) returns (StatusResponse) {}
400405
// Find Proxied HostInfo by instance ID
401406
rpc GetInfo(GetInfoRequest) returns (GetInfoResponse) {}
402407
// Exit the Gateway process.
403-
rpc Exit(google.protobuf.Empty) returns (google.protobuf.Empty) {}
408+
rpc Exit(ExitRequest) returns (google.protobuf.Empty) {}
404409
// Renew the proxy TLS certificate if certbot is enabled
405410
rpc RenewCert(google.protobuf.Empty) returns (RenewCertResponse) {}
406411
// Reload the proxy TLS certificate from files

dstack/gateway/src/admin_service.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use dstack_gateway_rpc::{
1010
admin_server::{AdminRpc, AdminServer},
1111
CertAttestationInfo, CertbotConfigResponse, ClearInstancePortPolicyRequest,
1212
CreateDnsCredentialRequest, DeleteDnsCredentialRequest, DeleteZtDomainRequest,
13-
DnsCredentialInfo, ForceReleaseCertLockRequest, GetDefaultDnsCredentialResponse,
13+
DnsCredentialInfo, ExitRequest, ForceReleaseCertLockRequest, GetDefaultDnsCredentialResponse,
1414
GetDnsCredentialRequest, GetInfoRequest, GetInfoResponse, GetInstanceHandshakesRequest,
1515
GetInstanceHandshakesResponse, GetInstancePortPolicyRequest, GetInstancePortPolicyResponse,
1616
GetMetaResponse, GetNodeStatusesResponse, GetZtDomainRequest, GlobalConnectionsStats,
@@ -82,8 +82,8 @@ impl AdminRpcHandler {
8282
}
8383

8484
impl AdminRpc for AdminRpcHandler {
85-
async fn exit(self) -> Result<()> {
86-
self.state.lock().exit();
85+
async fn exit(self, request: ExitRequest) -> Result<()> {
86+
self.state.lock().exit(request.force)
8787
}
8888

8989
async fn renew_cert(self) -> Result<RenewCertResponse> {

dstack/gateway/src/main.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,19 @@ async fn main() -> Result<()> {
347347
} else {
348348
tracing::info!("admin server authentication enabled");
349349
}
350-
rocket::custom(admin_figment)
350+
let admin_rocket = rocket::custom(admin_figment)
351351
.attach(auth_fairing)
352352
.mount("/", admin_auth::routes())
353353
.mount("/", web_routes::routes())
354354
.mount("/", prpc!(Proxy, AdminRpcHandler, trim: "Admin."))
355355
.mount("/prpc", prpc!(Proxy, AdminRpcHandler, trim: "Admin."))
356-
.manage(admin_state)
357-
.launch()
358-
.await
356+
.manage(admin_state.clone())
357+
.ignite()
358+
.await?;
359+
admin_state
360+
.lock()
361+
.set_admin_shutdown(admin_rocket.shutdown());
362+
admin_rocket.launch().await
359363
} else {
360364
std::future::pending().await
361365
}

dstack/gateway/src/main_service.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ pub(crate) struct ProxyState {
112112
/// Reference to KvStore for syncing changes
113113
kv_store: Arc<KvStore>,
114114
handshake_cache: Arc<LatestHandshakesCache>,
115+
admin_shutdown: Option<rocket::Shutdown>,
115116
}
116117

117118
/// Options for creating a Proxy instance
@@ -244,6 +245,7 @@ impl ProxyInner {
244245
state,
245246
kv_store: kv_store.clone(),
246247
handshake_cache: handshake_cache.clone(),
248+
admin_shutdown: None,
247249
});
248250
let auth_client = AuthClient::new(config.auth.clone());
249251
// Bootstrap WaveKV first if sync is enabled, so certbot can load certs from peers
@@ -1324,8 +1326,21 @@ impl ProxyState {
13241326
Ok(())
13251327
}
13261328

1327-
pub(crate) fn exit(&mut self) -> ! {
1328-
std::process::exit(0);
1329+
pub(crate) fn set_admin_shutdown(&mut self, shutdown: rocket::Shutdown) {
1330+
self.admin_shutdown = Some(shutdown);
1331+
}
1332+
1333+
pub(crate) fn exit(&self, force: bool) -> Result<()> {
1334+
if force {
1335+
std::process::exit(0);
1336+
}
1337+
1338+
let shutdown = self
1339+
.admin_shutdown
1340+
.as_ref()
1341+
.context("admin server shutdown handle is not initialized")?;
1342+
shutdown.notify();
1343+
Ok(())
13291344
}
13301345

13311346
pub(crate) fn refresh_state(&mut self) -> Result<()> {

0 commit comments

Comments
 (0)