mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 09:08:32 +02:00
fix(gRPC): Cache descriptor pools to avoid re-reflection; add manual “Refresh Schema” to force re-fetch (#317)
This commit is contained in:
@@ -156,6 +156,7 @@ async fn cmd_grpc_reflect<R: Runtime>(
|
|||||||
request_id: &str,
|
request_id: &str,
|
||||||
environment_id: Option<&str>,
|
environment_id: Option<&str>,
|
||||||
proto_files: Vec<String>,
|
proto_files: Vec<String>,
|
||||||
|
skip_cache: Option<bool>,
|
||||||
window: WebviewWindow<R>,
|
window: WebviewWindow<R>,
|
||||||
app_handle: AppHandle<R>,
|
app_handle: AppHandle<R>,
|
||||||
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
||||||
@@ -196,6 +197,7 @@ async fn cmd_grpc_reflect<R: Runtime>(
|
|||||||
&proto_files.iter().map(|p| PathBuf::from_str(p).unwrap()).collect(),
|
&proto_files.iter().map(|p| PathBuf::from_str(p).unwrap()).collect(),
|
||||||
&metadata,
|
&metadata,
|
||||||
workspace.setting_validate_certificates,
|
workspace.setting_validate_certificates,
|
||||||
|
skip_cache.unwrap_or(false),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| GenericError(e.to_string()))?)
|
.map_err(|e| GenericError(e.to_string()))?)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::{MethodDefinition, ServiceDefinition, json_schema};
|
|||||||
use hyper_rustls::HttpsConnector;
|
use hyper_rustls::HttpsConnector;
|
||||||
use hyper_util::client::legacy::Client;
|
use hyper_util::client::legacy::Client;
|
||||||
use hyper_util::client::legacy::connect::HttpConnector;
|
use hyper_util::client::legacy::connect::HttpConnector;
|
||||||
use log::warn;
|
use log::{info, warn};
|
||||||
pub use prost_reflect::DynamicMessage;
|
pub use prost_reflect::DynamicMessage;
|
||||||
use prost_reflect::{DescriptorPool, MethodDescriptor, ServiceDescriptor};
|
use prost_reflect::{DescriptorPool, MethodDescriptor, ServiceDescriptor};
|
||||||
use serde_json::Deserializer;
|
use serde_json::Deserializer;
|
||||||
@@ -244,6 +244,12 @@ impl GrpcHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GrpcHandle {
|
impl GrpcHandle {
|
||||||
|
/// Remove cached descriptor pool for the given key, if present.
|
||||||
|
pub fn invalidate_pool(&mut self, id: &str, uri: &str, proto_files: &Vec<PathBuf>) {
|
||||||
|
let key = make_pool_key(id, uri, proto_files);
|
||||||
|
self.pools.remove(&key);
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn reflect(
|
pub async fn reflect(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &str,
|
id: &str,
|
||||||
@@ -253,6 +259,13 @@ impl GrpcHandle {
|
|||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
let server_reflection = proto_files.is_empty();
|
let server_reflection = proto_files.is_empty();
|
||||||
|
let key = make_pool_key(id, uri, proto_files);
|
||||||
|
|
||||||
|
// If we already have a pool for this key, reuse it and avoid re-reflection
|
||||||
|
if self.pools.contains_key(&key) {
|
||||||
|
return Ok(server_reflection);
|
||||||
|
}
|
||||||
|
|
||||||
let pool = if server_reflection {
|
let pool = if server_reflection {
|
||||||
let full_uri = uri_from_str(uri)?;
|
let full_uri = uri_from_str(uri)?;
|
||||||
fill_pool_from_reflection(&full_uri, metadata, validate_certificates).await
|
fill_pool_from_reflection(&full_uri, metadata, validate_certificates).await
|
||||||
@@ -260,7 +273,7 @@ impl GrpcHandle {
|
|||||||
fill_pool_from_files(&self.app_handle, proto_files).await
|
fill_pool_from_files(&self.app_handle, proto_files).await
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
self.pools.insert(make_pool_key(id, uri, proto_files), pool.clone());
|
self.pools.insert(key, pool.clone());
|
||||||
Ok(server_reflection)
|
Ok(server_reflection)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,9 +284,13 @@ impl GrpcHandle {
|
|||||||
proto_files: &Vec<PathBuf>,
|
proto_files: &Vec<PathBuf>,
|
||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
|
skip_cache: bool,
|
||||||
) -> Result<Vec<ServiceDefinition>, String> {
|
) -> Result<Vec<ServiceDefinition>, String> {
|
||||||
// Ensure reflection is up-to-date
|
// Ensure we have a pool; reflect only if missing
|
||||||
self.reflect(id, uri, proto_files, metadata, validate_certificates).await?;
|
if skip_cache || self.get_pool(id, uri, proto_files).is_none() {
|
||||||
|
info!("Reflecting gRPC services for {} at {}", id, uri);
|
||||||
|
self.reflect(id, uri, proto_files, metadata, validate_certificates).await?;
|
||||||
|
}
|
||||||
|
|
||||||
let pool = self.get_pool(id, uri, proto_files).ok_or("Failed to get pool".to_string())?;
|
let pool = self.get_pool(id, uri, proto_files).ok_or("Failed to get pool".to_string())?;
|
||||||
Ok(self.services_from_pool(&pool))
|
Ok(self.services_from_pool(&pool))
|
||||||
@@ -312,8 +329,10 @@ impl GrpcHandle {
|
|||||||
metadata: &BTreeMap<String, String>,
|
metadata: &BTreeMap<String, String>,
|
||||||
validate_certificates: bool,
|
validate_certificates: bool,
|
||||||
) -> Result<GrpcConnection, String> {
|
) -> Result<GrpcConnection, String> {
|
||||||
let use_reflection =
|
let use_reflection = proto_files.is_empty();
|
||||||
|
if self.get_pool(id, uri, proto_files).is_none() {
|
||||||
self.reflect(id, uri, proto_files, metadata, validate_certificates).await?;
|
self.reflect(id, uri, proto_files, metadata, validate_certificates).await?;
|
||||||
|
}
|
||||||
let pool = self.get_pool(id, uri, proto_files).ok_or("Failed to get pool")?.clone();
|
let pool = self.get_pool(id, uri, proto_files).ok_or("Failed to get pool")?.clone();
|
||||||
let uri = uri_from_str(uri)?;
|
let uri = uri_from_str(uri)?;
|
||||||
let conn = get_transport(validate_certificates);
|
let conn = get_transport(validate_certificates);
|
||||||
|
|||||||
@@ -47,10 +47,14 @@ export function useGrpc(
|
|||||||
const reflect = useQuery<ReflectResponseService[], string>({
|
const reflect = useQuery<ReflectResponseService[], string>({
|
||||||
enabled: req != null,
|
enabled: req != null,
|
||||||
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl, protoFiles],
|
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl, protoFiles],
|
||||||
|
staleTime: Infinity,
|
||||||
|
refetchOnMount: false,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
refetchOnReconnect: false,
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
const environmentId = jotaiStore.get(activeEnvironmentIdAtom);
|
const environmentId = jotaiStore.get(activeEnvironmentIdAtom);
|
||||||
return minPromiseMillis<ReflectResponseService[]>(
|
return minPromiseMillis<ReflectResponseService[]>(
|
||||||
invokeCmd('cmd_grpc_reflect', { requestId, protoFiles, environmentId }),
|
invokeCmd('cmd_grpc_reflect', { requestId, protoFiles, environmentId, skipCache: true }),
|
||||||
300,
|
300,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user