1use std::sync::Arc;
2use std::sync::atomic::Ordering;
3
4use crate::async_counter::AsyncCounter;
5use rivet_envoy_protocol as protocol;
6use tokio::sync::oneshot;
7
8use crate::context::SharedContext;
9use crate::envoy::{ActorInfo, ToEnvoyMessage};
10use crate::metrics::METRICS;
11use crate::sqlite::{RemoteSqliteRequest, RemoteSqliteResponse, SqliteRequest, SqliteResponse};
12use crate::tunnel::HibernatingWebSocketMetadata;
13
14#[derive(Clone)]
16pub struct EnvoyHandle {
17 pub(crate) shared: Arc<SharedContext>,
18 pub(crate) started_rx: tokio::sync::watch::Receiver<()>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct ServerlessActorStart {
23 pub actor_id: String,
24 pub generation: u32,
25}
26
27impl EnvoyHandle {
28 #[doc(hidden)]
29 pub fn from_shared(shared: Arc<SharedContext>) -> Self {
30 Self {
31 shared,
32 started_rx: tokio::sync::watch::channel(()).1,
33 }
34 }
35
36 pub fn shutdown(&self, immediate: bool) {
37 self.shared.shutting_down.store(true, Ordering::Release);
38
39 if immediate {
40 let _ = crate::envoy::send_to_envoy_tx(&self.shared, ToEnvoyMessage::Stop);
41 } else {
42 let _ = crate::envoy::send_to_envoy_tx(&self.shared, ToEnvoyMessage::Shutdown);
43 }
44 }
45
46 pub fn is_stopped(&self) -> bool {
49 *self.shared.stopped_tx.borrow()
50 }
51
52 pub async fn wait_stopped(&self) {
62 let mut rx = self.shared.stopped_tx.subscribe();
63 if *rx.borrow_and_update() {
64 return;
65 }
66 let _ = rx.changed().await;
67 }
68
69 pub async fn shutdown_and_wait(&self, immediate: bool) {
71 self.shutdown(immediate);
72 self.wait_stopped().await;
73 }
74
75 pub async fn get_protocol_metadata(&self) -> Option<protocol::ProtocolMetadata> {
76 self.shared.protocol_metadata.lock().await.clone()
77 }
78
79 pub const PING_HEALTHY_THRESHOLD_MS: i64 = 20_000;
81
82 pub fn is_ping_healthy(&self) -> bool {
87 let last = self.shared.last_ping_ts.load(Ordering::Acquire);
88 if last == 0 {
89 return false;
90 }
91 crate::time::now_millis() - last < Self::PING_HEALTHY_THRESHOLD_MS
92 }
93
94 pub fn get_envoy_key(&self) -> &str {
95 &self.shared.envoy_key
96 }
97
98 pub fn endpoint(&self) -> &str {
99 &self.shared.config.endpoint
100 }
101
102 pub fn token(&self) -> Option<&str> {
103 self.shared.config.token.as_deref()
104 }
105
106 #[doc(hidden)]
110 pub fn connection_session(&self) -> Option<u64> {
111 let session = self.shared.connection_session.load(Ordering::Acquire);
112 (session != 0).then_some(session)
113 }
114
115 #[doc(hidden)]
116 pub fn subscribe_connection_session(&self) -> tokio::sync::watch::Receiver<u64> {
117 self.shared.connection_session_tx.subscribe()
118 }
119
120 pub fn namespace(&self) -> &str {
121 &self.shared.config.namespace
122 }
123
124 pub fn active_actor_count(&self) -> usize {
125 let guard = self
126 .shared
127 .actors
128 .lock()
129 .expect("shared actor registry poisoned");
130 guard
131 .values()
132 .map(|generations| {
133 generations
134 .values()
135 .filter(|actor| !actor.handle.is_closed())
136 .count()
137 })
138 .sum()
139 }
140
141 pub fn pool_name(&self) -> &str {
142 &self.shared.config.pool_name
143 }
144
145 pub async fn started(&self) -> anyhow::Result<()> {
146 self.started_rx
147 .clone()
148 .changed()
149 .await
150 .map_err(|_| anyhow::anyhow!("envoy stopped before startup completed"))?;
151 Ok(())
152 }
153
154 pub fn sleep_actor(&self, actor_id: String, generation: Option<u32>, error: Option<String>) {
160 let _ = crate::envoy::send_to_envoy_tx(
161 &self.shared,
162 ToEnvoyMessage::ActorIntent {
163 actor_id,
164 generation,
165 intent: protocol::ActorIntent::ActorIntentSleep,
166 error,
167 },
168 );
169 }
170
171 pub fn stop_actor(&self, actor_id: String, generation: Option<u32>) {
176 let _ = crate::envoy::send_to_envoy_tx(
177 &self.shared,
178 ToEnvoyMessage::ActorIntent {
179 actor_id,
180 generation,
181 intent: protocol::ActorIntent::ActorIntentStop,
182 error: None,
183 },
184 );
185 }
186
187 pub async fn get_actor(&self, actor_id: &str, generation: Option<u32>) -> Option<ActorInfo> {
188 let (tx, rx) = tokio::sync::oneshot::channel();
189 crate::envoy::send_to_envoy_tx(
190 &self.shared,
191 ToEnvoyMessage::GetActor {
192 actor_id: actor_id.to_string(),
193 generation,
194 response_tx: tx,
195 },
196 )
197 .ok()?;
198 rx.await.ok().flatten()
199 }
200
201 pub async fn wait_actor_registered_then_stopped(&self, actor_id: &str, generation: u32) {
202 let mut registered = false;
203 loop {
204 let notified = self.shared.actors_notify.notified();
205 if self.is_stopped() {
206 return;
207 }
208
209 let actor_is_registered = {
210 let guard = self
211 .shared
212 .actors
213 .lock()
214 .expect("shared actor registry poisoned");
215 guard
216 .get(actor_id)
217 .and_then(|generations| generations.get(&generation))
218 .is_some()
219 };
220
221 if registered && !actor_is_registered {
222 return;
223 }
224 if actor_is_registered {
225 registered = true;
226 }
227
228 tokio::select! {
229 _ = notified => {}
230 _ = self.wait_stopped() => return,
231 }
232 }
233 }
234
235 pub async fn wait_actors_drained(&self) {
239 loop {
240 let notified = self.shared.actors_notify.notified();
241 tokio::pin!(notified);
242 notified.as_mut().enable();
245
246 if self.is_stopped() || self.active_actor_count() == 0 {
247 return;
248 }
249
250 tokio::select! {
251 _ = notified => {}
252 _ = self.wait_stopped() => return,
253 }
254 }
255 }
256
257 pub fn http_request_counter(
258 &self,
259 actor_id: &str,
260 generation: Option<u32>,
261 ) -> Option<Arc<AsyncCounter>> {
262 let guard = self
263 .shared
264 .actors
265 .lock()
266 .expect("shared actor registry poisoned");
267 let generations = guard.get(actor_id)?;
268
269 if let Some(generation) = generation {
270 return generations
271 .get(&generation)
272 .map(|actor| actor.active_http_request_count.clone());
273 }
274
275 generations
276 .iter()
277 .filter(|(_, actor)| !actor.handle.is_closed())
278 .max_by_key(|(generation, _)| *generation)
279 .map(|(_, actor)| actor.active_http_request_count.clone())
280 }
281
282 pub async fn get_active_http_request_count(
283 &self,
284 actor_id: &str,
285 generation: Option<u32>,
286 ) -> Option<usize> {
287 self.http_request_counter(actor_id, generation)
288 .map(|counter| counter.load())
289 }
290
291 pub fn hibernatable_connection_is_live(
292 &self,
293 actor_id: &str,
294 _generation: Option<u32>,
295 gateway_id: protocol::GatewayId,
296 request_id: protocol::RequestId,
297 ) -> bool {
298 let key = make_ws_key(&gateway_id, &request_id);
299 if self
300 .shared
301 .live_tunnel_requests
302 .lock()
303 .expect("shared live tunnel request registry poisoned")
304 .get(&key)
305 .is_some_and(|live_actor_id| live_actor_id == actor_id)
306 {
307 return true;
308 }
309
310 self.shared
311 .pending_hibernation_restores
312 .lock()
313 .expect("shared pending hibernation restore registry poisoned")
314 .get(actor_id)
315 .is_some_and(|entries| {
316 entries
317 .iter()
318 .any(|entry| entry.gateway_id == gateway_id && entry.request_id == request_id)
319 })
320 }
321
322 pub fn set_alarm(&self, actor_id: String, alarm_ts: Option<i64>, generation: Option<u32>) {
323 self.set_alarm_with_ack(actor_id, alarm_ts, generation, None);
324 }
325
326 pub fn set_alarm_with_ack(
327 &self,
328 actor_id: String,
329 alarm_ts: Option<i64>,
330 generation: Option<u32>,
331 ack_tx: Option<oneshot::Sender<()>>,
332 ) {
333 let _ = crate::envoy::send_to_envoy_tx(
334 &self.shared,
335 ToEnvoyMessage::SetAlarm {
336 actor_id,
337 generation,
338 alarm_ts,
339 ack_tx,
340 },
341 );
342 }
343
344 pub async fn kv_get(
345 &self,
346 actor_id: String,
347 keys: Vec<Vec<u8>>,
348 ) -> anyhow::Result<Vec<Option<Vec<u8>>>> {
349 let request_keys = keys.clone();
350 let response = self
351 .send_kv_request(
352 actor_id,
353 protocol::KvRequestData::KvGetRequest(protocol::KvGetRequest { keys }),
354 )
355 .await?;
356
357 match response {
358 protocol::KvResponseData::KvGetResponse(resp) => {
359 let mut result = Vec::with_capacity(request_keys.len());
360 for requested_key in &request_keys {
361 let mut found = false;
362 for (i, resp_key) in resp.keys.iter().enumerate() {
363 if requested_key == resp_key {
364 result.push(Some(resp.values[i].clone()));
365 found = true;
366 break;
367 }
368 }
369 if !found {
370 result.push(None);
371 }
372 }
373 Ok(result)
374 }
375 protocol::KvResponseData::KvErrorResponse(e) => {
376 anyhow::bail!("{}", e.message)
377 }
378 _ => anyhow::bail!("unexpected KV response type"),
379 }
380 }
381
382 pub async fn kv_list_all(
383 &self,
384 actor_id: String,
385 reverse: Option<bool>,
386 limit: Option<u64>,
387 ) -> anyhow::Result<Vec<(Vec<u8>, Vec<u8>)>> {
388 let response = self
389 .send_kv_request(
390 actor_id,
391 protocol::KvRequestData::KvListRequest(protocol::KvListRequest {
392 query: protocol::KvListQuery::KvListAllQuery,
393 reverse,
394 limit,
395 }),
396 )
397 .await?;
398 parse_list_response(response)
399 }
400
401 pub async fn kv_list_range(
402 &self,
403 actor_id: String,
404 start: Vec<u8>,
405 end: Vec<u8>,
406 exclusive: bool,
407 reverse: Option<bool>,
408 limit: Option<u64>,
409 ) -> anyhow::Result<Vec<(Vec<u8>, Vec<u8>)>> {
410 let response = self
411 .send_kv_request(
412 actor_id,
413 protocol::KvRequestData::KvListRequest(protocol::KvListRequest {
414 query: protocol::KvListQuery::KvListRangeQuery(protocol::KvListRangeQuery {
415 start,
416 end,
417 exclusive,
418 }),
419 reverse,
420 limit,
421 }),
422 )
423 .await?;
424 parse_list_response(response)
425 }
426
427 pub async fn kv_list_prefix(
428 &self,
429 actor_id: String,
430 prefix: Vec<u8>,
431 reverse: Option<bool>,
432 limit: Option<u64>,
433 ) -> anyhow::Result<Vec<(Vec<u8>, Vec<u8>)>> {
434 let response = self
435 .send_kv_request(
436 actor_id,
437 protocol::KvRequestData::KvListRequest(protocol::KvListRequest {
438 query: protocol::KvListQuery::KvListPrefixQuery(protocol::KvListPrefixQuery {
439 key: prefix,
440 }),
441 reverse,
442 limit,
443 }),
444 )
445 .await?;
446 parse_list_response(response)
447 }
448
449 pub async fn kv_put(
450 &self,
451 actor_id: String,
452 entries: Vec<(Vec<u8>, Vec<u8>)>,
453 ) -> anyhow::Result<()> {
454 let (keys, values): (Vec<_>, Vec<_>) = entries.into_iter().unzip();
455 let response = self
456 .send_kv_request(
457 actor_id,
458 protocol::KvRequestData::KvPutRequest(protocol::KvPutRequest { keys, values }),
459 )
460 .await?;
461 match response {
462 protocol::KvResponseData::KvPutResponse => Ok(()),
463 protocol::KvResponseData::KvErrorResponse(e) => anyhow::bail!("{}", e.message),
464 _ => anyhow::bail!("unexpected KV response type"),
465 }
466 }
467
468 pub async fn kv_delete(&self, actor_id: String, keys: Vec<Vec<u8>>) -> anyhow::Result<()> {
469 let response = self
470 .send_kv_request(
471 actor_id,
472 protocol::KvRequestData::KvDeleteRequest(protocol::KvDeleteRequest { keys }),
473 )
474 .await?;
475 match response {
476 protocol::KvResponseData::KvDeleteResponse => Ok(()),
477 protocol::KvResponseData::KvErrorResponse(e) => anyhow::bail!("{}", e.message),
478 _ => anyhow::bail!("unexpected KV response type"),
479 }
480 }
481
482 pub async fn kv_delete_range(
483 &self,
484 actor_id: String,
485 start: Vec<u8>,
486 end: Vec<u8>,
487 ) -> anyhow::Result<()> {
488 let response = self
489 .send_kv_request(
490 actor_id,
491 protocol::KvRequestData::KvDeleteRangeRequest(protocol::KvDeleteRangeRequest {
492 start,
493 end,
494 }),
495 )
496 .await?;
497 match response {
498 protocol::KvResponseData::KvDeleteResponse => Ok(()),
499 protocol::KvResponseData::KvErrorResponse(e) => anyhow::bail!("{}", e.message),
500 _ => anyhow::bail!("unexpected KV response type"),
501 }
502 }
503
504 pub async fn kv_drop(&self, actor_id: String) -> anyhow::Result<()> {
505 let response = self
506 .send_kv_request(actor_id, protocol::KvRequestData::KvDropRequest)
507 .await?;
508 match response {
509 protocol::KvResponseData::KvDropResponse => Ok(()),
510 protocol::KvResponseData::KvErrorResponse(e) => anyhow::bail!("{}", e.message),
511 _ => anyhow::bail!("unexpected KV response type"),
512 }
513 }
514
515 pub async fn sqlite_get_pages(
516 &self,
517 request: protocol::SqliteGetPagesRequest,
518 ) -> anyhow::Result<protocol::SqliteGetPagesResponse> {
519 match self
520 .send_sqlite_request(SqliteRequest::GetPages(request))
521 .await?
522 {
523 SqliteResponse::GetPages(response) => Ok(response),
524 _ => anyhow::bail!("unexpected sqlite get_pages response type"),
525 }
526 }
527
528 pub async fn sqlite_commit(
529 &self,
530 request: protocol::SqliteCommitRequest,
531 ) -> anyhow::Result<protocol::SqliteCommitResponse> {
532 match self
533 .send_sqlite_request(SqliteRequest::Commit(request))
534 .await?
535 {
536 SqliteResponse::Commit(response) => Ok(response),
537 _ => anyhow::bail!("unexpected sqlite commit response type"),
538 }
539 }
540
541 pub async fn sqlite_commit_stage_begin(
543 &self,
544 request: protocol::SqliteCommitStageBeginRequest,
545 ) -> anyhow::Result<protocol::SqliteCommitStageBeginResponse> {
546 match self
547 .send_sqlite_request(SqliteRequest::CommitStageBegin(request))
548 .await?
549 {
550 SqliteResponse::CommitStageBegin(response) => Ok(response),
551 _ => anyhow::bail!("unexpected sqlite commit_stage_begin response type"),
552 }
553 }
554
555 pub async fn sqlite_commit_stage_segment(
556 &self,
557 request: protocol::SqliteCommitStageSegmentRequest,
558 ) -> anyhow::Result<protocol::SqliteCommitStageSegmentResponse> {
559 match self
560 .send_sqlite_request(SqliteRequest::CommitStageSegment(request))
561 .await?
562 {
563 SqliteResponse::CommitStageSegment(response) => Ok(response),
564 _ => anyhow::bail!("unexpected sqlite commit_stage_segment response type"),
565 }
566 }
567
568 pub async fn sqlite_commit_finalize(
570 &self,
571 request: protocol::SqliteCommitFinalizeRequest,
572 ) -> anyhow::Result<protocol::SqliteCommitFinalizeResponse> {
573 match self
574 .send_sqlite_request(SqliteRequest::CommitFinalize(request))
575 .await?
576 {
577 SqliteResponse::CommitFinalize(response) => Ok(response),
578 _ => anyhow::bail!("unexpected sqlite commit_finalize response type"),
579 }
580 }
581
582 pub async fn remote_sqlite_exec(
583 &self,
584 request: protocol::SqliteExecRequest,
585 ) -> anyhow::Result<protocol::SqliteExecResponse> {
586 match self
587 .send_remote_sqlite_request(RemoteSqliteRequest::Exec(request), None)
588 .await?
589 .response
590 {
591 RemoteSqliteResponse::Exec(response) => Ok(response),
592 _ => anyhow::bail!("unexpected remote sqlite exec response type"),
593 }
594 }
595
596 pub async fn remote_sqlite_execute(
597 &self,
598 request: protocol::SqliteExecuteRequest,
599 ) -> anyhow::Result<protocol::SqliteExecuteResponse> {
600 match self
601 .send_remote_sqlite_request(RemoteSqliteRequest::Execute(request), None)
602 .await?
603 .response
604 {
605 RemoteSqliteResponse::Execute(response) => Ok(response),
606 _ => anyhow::bail!("unexpected remote sqlite execute response type"),
607 }
608 }
609
610 pub async fn remote_sqlite_execute_batch(
611 &self,
612 request: protocol::SqliteExecuteBatchRequest,
613 ) -> anyhow::Result<protocol::SqliteExecuteBatchResponse> {
614 match self
615 .send_remote_sqlite_request(RemoteSqliteRequest::ExecuteBatch(request), None)
616 .await?
617 .response
618 {
619 RemoteSqliteResponse::ExecuteBatch(response) => Ok(response),
620 _ => anyhow::bail!("unexpected remote sqlite execute batch response type"),
621 }
622 }
623
624 #[doc(hidden)]
629 pub async fn remote_sqlite_exec_with_session(
630 &self,
631 request: protocol::SqliteExecRequest,
632 expected_session: Option<u64>,
633 ) -> anyhow::Result<(protocol::SqliteExecResponse, u64)> {
634 let envelope = self
635 .send_remote_sqlite_request(RemoteSqliteRequest::Exec(request), expected_session)
636 .await?;
637 match envelope.response {
638 RemoteSqliteResponse::Exec(response) => Ok((response, envelope.session)),
639 _ => anyhow::bail!("unexpected remote sqlite exec response type"),
640 }
641 }
642
643 #[doc(hidden)]
644 pub async fn remote_sqlite_execute_with_session(
645 &self,
646 request: protocol::SqliteExecuteRequest,
647 expected_session: Option<u64>,
648 ) -> anyhow::Result<(protocol::SqliteExecuteResponse, u64)> {
649 let envelope = self
650 .send_remote_sqlite_request(RemoteSqliteRequest::Execute(request), expected_session)
651 .await?;
652 match envelope.response {
653 RemoteSqliteResponse::Execute(response) => Ok((response, envelope.session)),
654 _ => anyhow::bail!("unexpected remote sqlite execute response type"),
655 }
656 }
657
658 pub fn restore_hibernating_requests(
659 &self,
660 actor_id: String,
661 meta_entries: Vec<HibernatingWebSocketMetadata>,
662 ) {
663 self.shared
664 .pending_hibernation_restores
665 .lock()
666 .expect("shared pending hibernation restore registry poisoned")
667 .insert(actor_id, meta_entries);
668 }
669
670 pub(crate) fn take_pending_hibernation_restore(
671 &self,
672 actor_id: &str,
673 ) -> Option<Vec<HibernatingWebSocketMetadata>> {
674 self.shared
675 .pending_hibernation_restores
676 .lock()
677 .expect("shared pending hibernation restore registry poisoned")
678 .remove(actor_id)
679 }
680
681 pub fn send_hibernatable_ws_message_ack(
682 &self,
683 gateway_id: protocol::GatewayId,
684 request_id: protocol::RequestId,
685 client_message_index: u16,
686 ) {
687 let _ = crate::envoy::send_to_envoy_tx(
688 &self.shared,
689 ToEnvoyMessage::HwsAck {
690 gateway_id,
691 request_id,
692 envoy_message_index: client_message_index,
693 },
694 );
695 }
696
697 pub(crate) async fn rebind_hibernating_websocket(
698 &self,
699 actor_id: String,
700 generation: u32,
701 gateway_id: protocol::GatewayId,
702 request_id: protocol::RequestId,
703 ) -> bool {
704 let (response_tx, response_rx) = oneshot::channel();
705 if crate::envoy::send_to_envoy_tx(
706 &self.shared,
707 ToEnvoyMessage::RebindWebSocket {
708 actor_id,
709 generation,
710 gateway_id,
711 request_id,
712 response_tx,
713 },
714 )
715 .is_err()
716 {
717 return false;
718 }
719 response_rx.await.unwrap_or(false)
720 }
721
722 pub async fn start_serverless_actor(&self, payload: &[u8]) -> anyhow::Result<()> {
725 tracing::debug!(
726 envoy_key = %self.shared.envoy_key,
727 payload_len = payload.len(),
728 "received serverless start request"
729 );
730 let (message, _) = decode_serverless_actor_start_payload(payload)?;
731
732 self.started().await?;
734
735 tracing::debug!(
736 envoy_key = %self.shared.envoy_key,
737 data = crate::stringify::stringify_to_envoy(&message),
738 "received serverless start"
739 );
740 crate::envoy::send_to_envoy_tx(
741 &self.shared,
742 ToEnvoyMessage::ConnMessage {
743 message,
744 session: self.shared.connection_session.load(Ordering::Acquire),
745 },
746 )
747 .map_err(|_| anyhow::anyhow!("envoy channel closed"))?;
748
749 Ok(())
750 }
751
752 pub fn decode_serverless_actor_start(
753 &self,
754 payload: &[u8],
755 ) -> anyhow::Result<ServerlessActorStart> {
756 let (_, actor_start) = decode_serverless_actor_start_payload(payload)?;
757 Ok(actor_start)
758 }
759}
760
761fn decode_serverless_actor_start_payload(
762 payload: &[u8],
763) -> anyhow::Result<(protocol::ToEnvoy, ServerlessActorStart)> {
764 use vbare::OwnedVersionedData;
765
766 if payload.len() < 2 {
767 anyhow::bail!("serverless start payload too short");
768 }
769
770 let version = u16::from_le_bytes([payload[0], payload[1]]);
771 if version != protocol::PROTOCOL_VERSION {
772 anyhow::bail!(
773 "serverless start payload does not match protocol version: {version} vs {}",
774 protocol::PROTOCOL_VERSION
775 );
776 }
777
778 let message = match crate::protocol::versioned::ToEnvoy::deserialize(&payload[2..], version) {
779 Ok(message) => message,
780 Err(err) if version == protocol::PROTOCOL_VERSION => {
781 tracing::debug!(
782 ?err,
783 "serverless start payload failed current-version decode, retrying as v1-compatible body"
784 );
785 crate::protocol::versioned::ToEnvoy::deserialize(
786 &payload[2..],
787 protocol::PROTOCOL_VERSION - 1,
788 )?
789 }
790 Err(err) => return Err(err),
791 };
792
793 let protocol::ToEnvoy::ToEnvoyCommands(ref commands) = message else {
794 anyhow::bail!("invalid serverless payload: expected ToEnvoyCommands");
795 };
796 if commands.len() != 1 {
797 anyhow::bail!("invalid serverless payload: expected exactly 1 command");
798 }
799 if !matches!(commands[0].inner, protocol::Command::CommandStartActor(_)) {
800 anyhow::bail!("invalid serverless payload: expected CommandStartActor");
801 }
802
803 let actor_start = ServerlessActorStart {
804 actor_id: commands[0].checkpoint.actor_id.clone(),
805 generation: commands[0].checkpoint.generation,
806 };
807
808 Ok((message, actor_start))
809}
810
811impl EnvoyHandle {
812 async fn send_kv_request(
813 &self,
814 actor_id: String,
815 data: protocol::KvRequestData,
816 ) -> anyhow::Result<protocol::KvResponseData> {
817 let (tx, rx) = tokio::sync::oneshot::channel();
818 crate::envoy::send_to_envoy_tx(
819 &self.shared,
820 ToEnvoyMessage::KvRequest {
821 actor_id,
822 data,
823 response_tx: tx,
824 },
825 )
826 .map_err(|_| anyhow::anyhow!("envoy channel closed"))?;
827 rx.await
828 .map_err(|_| anyhow::anyhow!("kv response channel closed"))?
829 }
830
831 async fn send_sqlite_request(&self, request: SqliteRequest) -> anyhow::Result<SqliteResponse> {
832 let kind = request.kind();
833 let total_start = crate::time::Instant::now();
834 let submit_start = crate::time::Instant::now();
835 let (tx, rx) = tokio::sync::oneshot::channel();
836 crate::envoy::send_to_envoy_tx(
837 &self.shared,
838 ToEnvoyMessage::SqliteRequest {
839 request,
840 response_tx: tx,
841 },
842 )
843 .map_err(|_| anyhow::anyhow!("envoy channel closed"))?;
844 let submit_elapsed = submit_start.elapsed();
845 METRICS
846 .sqlite_request_submit_duration_seconds
847 .with_label_values(&[kind])
848 .observe(submit_elapsed.as_secs_f64());
849
850 let wait_start = crate::time::Instant::now();
851 let result = rx
852 .await
853 .map_err(|_| anyhow::anyhow!("sqlite response channel closed"))?;
854 let wait_elapsed = wait_start.elapsed();
855 METRICS
856 .sqlite_request_wait_duration_seconds
857 .with_label_values(&[kind])
858 .observe(wait_elapsed.as_secs_f64());
859 METRICS
860 .sqlite_request_total_duration_seconds
861 .with_label_values(&[kind])
862 .observe(total_start.elapsed().as_secs_f64());
863 result
864 }
865
866 async fn send_remote_sqlite_request(
867 &self,
868 request: RemoteSqliteRequest,
869 expected_session: Option<u64>,
870 ) -> anyhow::Result<crate::sqlite::RemoteSqliteResponseEnvelope> {
871 let kind = request.kind();
872 let total_start = crate::time::Instant::now();
873 let submit_start = crate::time::Instant::now();
874 let (tx, rx) = tokio::sync::oneshot::channel();
875 crate::envoy::send_to_envoy_tx(
876 &self.shared,
877 ToEnvoyMessage::RemoteSqliteRequest {
878 request,
879 expected_session,
880 response_tx: tx,
881 },
882 )
883 .map_err(|_| anyhow::anyhow!("envoy channel closed"))?;
884 let submit_elapsed = submit_start.elapsed();
885 METRICS
886 .sqlite_request_submit_duration_seconds
887 .with_label_values(&[kind])
888 .observe(submit_elapsed.as_secs_f64());
889
890 let wait_start = crate::time::Instant::now();
891 let result = rx
892 .await
893 .map_err(|_| anyhow::anyhow!("remote sqlite response channel closed"))?;
894 let wait_elapsed = wait_start.elapsed();
895 METRICS
896 .sqlite_request_wait_duration_seconds
897 .with_label_values(&[kind])
898 .observe(wait_elapsed.as_secs_f64());
899 METRICS
900 .sqlite_request_total_duration_seconds
901 .with_label_values(&[kind])
902 .observe(total_start.elapsed().as_secs_f64());
903 result
904 }
905}
906
907fn make_ws_key(gateway_id: &protocol::GatewayId, request_id: &protocol::RequestId) -> [u8; 8] {
908 let mut key = [0u8; 8];
909 key[..4].copy_from_slice(gateway_id);
910 key[4..].copy_from_slice(request_id);
911 key
912}
913
914fn parse_list_response(
915 response: protocol::KvResponseData,
916) -> anyhow::Result<Vec<(Vec<u8>, Vec<u8>)>> {
917 match response {
918 protocol::KvResponseData::KvListResponse(resp) => {
919 Ok(resp.keys.into_iter().zip(resp.values).collect())
920 }
921 protocol::KvResponseData::KvErrorResponse(e) => anyhow::bail!("{}", e.message),
922 _ => anyhow::bail!("unexpected KV response type"),
923 }
924}