Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
OpenDAS
dynamo
Commits
6a358f7c
Unverified
Commit
6a358f7c
authored
Aug 22, 2025
by
Graham King
Committed by
GitHub
Aug 22, 2025
Browse files
chore(llm): Rename protocols::Endpoint to EndpointId (#2615)
parent
02e59bba
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
131 additions
and
189 deletions
+131
-189
lib/bindings/python/rust/llm/entrypoint.rs
lib/bindings/python/rust/llm/entrypoint.rs
+2
-9
lib/llm/src/discovery/model_entry.rs
lib/llm/src/discovery/model_entry.rs
+5
-4
lib/llm/src/discovery/watcher.rs
lib/llm/src/discovery/watcher.rs
+1
-1
lib/llm/src/entrypoint/input/endpoint.rs
lib/llm/src/entrypoint/input/endpoint.rs
+2
-2
lib/llm/src/http/service/clear_kv_blocks.rs
lib/llm/src/http/service/clear_kv_blocks.rs
+2
-14
lib/llm/src/http/service/health.rs
lib/llm/src/http/service/health.rs
+1
-28
lib/llm/src/local_model.rs
lib/llm/src/local_model.rs
+2
-2
lib/llm/src/mocker/engine.rs
lib/llm/src/mocker/engine.rs
+5
-5
lib/llm/src/mocker/scheduler.rs
lib/llm/src/mocker/scheduler.rs
+1
-13
lib/llm/src/protocols/common/llm_backend.rs
lib/llm/src/protocols/common/llm_backend.rs
+0
-5
lib/runtime/src/component.rs
lib/runtime/src/component.rs
+1
-1
lib/runtime/src/protocols.rs
lib/runtime/src/protocols.rs
+103
-73
lib/runtime/src/protocols/annotated.rs
lib/runtime/src/protocols/annotated.rs
+0
-16
lib/runtime/src/storage/key_value_store/nats.rs
lib/runtime/src/storage/key_value_store/nats.rs
+6
-16
No files found.
lib/bindings/python/rust/llm/entrypoint.rs
View file @
6a358f7c
...
...
@@ -13,7 +13,7 @@ use dynamo_llm::kv_router::KvRouterConfig as RsKvRouterConfig;
use
dynamo_llm
::
local_model
::
DEFAULT_HTTP_PORT
;
use
dynamo_llm
::
local_model
::{
LocalModel
,
LocalModelBuilder
};
use
dynamo_llm
::
mocker
::
protocols
::
MockEngineArgs
;
use
dynamo_runtime
::
protocols
::
Endpoint
as
EndpointId
;
use
dynamo_runtime
::
protocols
::
EndpointId
;
use
crate
::
RouterMode
;
...
...
@@ -130,14 +130,7 @@ impl EntrypointArgs {
tls_key_path
:
Option
<
PathBuf
>
,
extra_engine_args
:
Option
<
PathBuf
>
,
)
->
PyResult
<
Self
>
{
let
endpoint_id_obj
:
Option
<
EndpointId
>
=
match
endpoint_id
{
Some
(
eid
)
=>
Some
(
eid
.parse
()
.map_err
(|
_
|
{
PyErr
::
new
::
<
pyo3
::
exceptions
::
PyValueError
,
_
>
(
format!
(
"Invalid endpoint_id format: {eid}"
))
})
?
),
None
=>
None
,
};
let
endpoint_id_obj
:
Option
<
EndpointId
>
=
endpoint_id
.as_deref
()
.map
(
EndpointId
::
from
);
if
(
tls_cert_path
.is_some
()
&&
tls_key_path
.is_none
())
||
(
tls_cert_path
.is_none
()
&&
tls_key_path
.is_some
())
{
...
...
lib/llm/src/discovery/model_entry.rs
View file @
6a358f7c
...
...
@@ -21,11 +21,12 @@ use crate::{
#[derive(Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq)]
pub
struct
ModelEntry
{
/// Public name of the model
///
This will be u
sed to identify the model in the HTTP service from the value used in an
an
OpenAI ChatRequest.
///
U
sed to identify the model in the HTTP service from the value used in an OpenAI ChatRequest.
pub
name
:
String
,
/// How to address this on the network
pub
endpoint
:
protocols
::
Endpoint
,
#[serde(rename
=
"endpoint"
)]
pub
endpoint_id
:
protocols
::
EndpointId
,
/// Specifies whether the model is a chat, completions, etc model.
pub
model_type
:
ModelType
,
...
...
@@ -45,8 +46,8 @@ impl ModelEntry {
matches!
(
self
.model_type
,
ModelType
::
Backend
)
}
/// Fetch the ModelDeploymentCard from
NATS
.
/// This does not touch it
'
s fields so you may need to call move_from_nats on it.
/// Fetch the ModelDeploymentCard from
etcd
.
/// This does not touch its fields so you may need to call move_from_nats on it.
pub
async
fn
load_mdc
(
&
self
,
etcd_client
:
&
etcd
::
Client
,
...
...
lib/llm/src/discovery/watcher.rs
View file @
6a358f7c
...
...
@@ -268,7 +268,7 @@ impl ModelWatcher {
// Handles a PUT event from etcd, this usually means adding a new model to the list of served
// models.
async
fn
handle_put
(
&
self
,
model_entry
:
&
ModelEntry
)
->
anyhow
::
Result
<
()
>
{
let
endpoint_id
=
model_entry
.endpoint
.clone
()
;
let
endpoint_id
=
&
model_entry
.endpoint
_id
;
let
component
=
self
.drt
.namespace
(
&
endpoint_id
.namespace
)
?
...
...
lib/llm/src/entrypoint/input/endpoint.rs
View file @
6a358f7c
...
...
@@ -20,7 +20,7 @@ use dynamo_runtime::engine::AsyncEngineStream;
use
dynamo_runtime
::
pipeline
::{
network
::
Ingress
,
Context
,
ManyOut
,
Operator
,
SegmentSource
,
ServiceBackend
,
SingleIn
,
Source
,
};
use
dynamo_runtime
::{
protocols
::
Endpoint
as
EndpointId
,
DistributedRuntime
};
use
dynamo_runtime
::{
protocols
::
EndpointId
,
DistributedRuntime
};
use
crate
::
entrypoint
::
EngineConfig
;
...
...
@@ -141,7 +141,7 @@ pub async fn run(
#[cfg(feature
=
"integration"
)]
mod
integration_tests
{
use
super
::
*
;
use
dynamo_runtime
::
protocols
::
Endpoint
as
EndpointId
;
use
dynamo_runtime
::
protocols
::
EndpointId
;
async
fn
create_test_environment
()
->
anyhow
::
Result
<
(
DistributedRuntime
,
EngineConfig
)
>
{
// Create a minimal distributed runtime and engine config for testing
...
...
lib/llm/src/http/service/clear_kv_blocks.rs
View file @
6a358f7c
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use
super
::{
service_v2
,
RouteDoc
};
use
axum
::{
http
::
Method
,
response
::
IntoResponse
,
routing
::
post
,
Json
,
Router
};
...
...
@@ -88,8 +76,8 @@ async fn clear_kv_blocks_handler(
// create client for each model entry
for
entry
in
&
model_entries
{
let
namespace
=
&
entry
.endpoint.namespace
;
let
component
=
&
entry
.endpoint.component
;
let
namespace
=
&
entry
.endpoint
_id
.namespace
;
let
component
=
&
entry
.endpoint
_id
.component
;
let
entry_name
=
entry
.name
.to_string
();
tracing
::
debug!
(
"Processing worker group: {}/{}"
,
namespace
,
component
);
...
...
lib/llm/src/http/service/health.rs
View file @
6a358f7c
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use
super
::{
service_v2
,
RouteDoc
};
use
axum
::{
http
::
Method
,
http
::
StatusCode
,
response
::
IntoResponse
,
routing
::
get
,
Json
,
Router
};
...
...
@@ -104,7 +77,7 @@ async fn health_handler(
}
else
{
let
endpoints
:
Vec
<
String
>
=
model_entries
.iter
()
.map
(|
entry
|
entry
.endpoint
.as_url
())
.map
(|
entry
|
entry
.endpoint
_id
.as_url
())
.collect
();
(
StatusCode
::
OK
,
...
...
lib/llm/src/local_model.rs
View file @
6a358f7c
...
...
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
use
std
::
sync
::
Arc
;
use
anyhow
::
Context
as
_
;
use
dynamo_runtime
::
protocols
::
Endpoint
as
EndpointId
;
use
dynamo_runtime
::
protocols
::
EndpointId
;
use
dynamo_runtime
::
slug
::
Slug
;
use
dynamo_runtime
::
traits
::
DistributedRuntimeProvider
;
use
dynamo_runtime
::{
...
...
@@ -402,7 +402,7 @@ impl LocalModel {
tracing
::
debug!
(
"Registering with etcd as {network_name}"
);
let
model_registration
=
ModelEntry
{
name
:
self
.display_name
()
.to_string
(),
endpoint
:
endpoint
.id
(),
endpoint
_id
:
endpoint
.id
(),
model_type
,
runtime_config
:
Some
(
self
.runtime_config
.clone
()),
};
...
...
lib/llm/src/mocker/engine.rs
View file @
6a358f7c
...
...
@@ -440,7 +440,7 @@ impl AnnotatedMockEngine {
pub
fn
new
(
inner
:
MockVllmEngine
,
distributed_runtime
:
DistributedRuntime
,
endpoint
:
dynamo_runtime
::
protocols
::
Endpoint
,
endpoint
_id
:
dynamo_runtime
::
protocols
::
Endpoint
Id
,
)
->
Self
{
let
inner
=
Arc
::
new
(
inner
);
let
inner_clone
=
inner
.clone
();
...
...
@@ -449,13 +449,13 @@ impl AnnotatedMockEngine {
tokio
::
spawn
(
async
move
{
loop
{
// Try to create component
let
Ok
(
namespace
)
=
distributed_runtime
.namespace
(
&
endpoint
.namespace
)
else
{
let
Ok
(
namespace
)
=
distributed_runtime
.namespace
(
&
endpoint
_id
.namespace
)
else
{
tracing
::
debug!
(
"Namespace not available yet, retrying..."
);
tokio
::
time
::
sleep
(
Duration
::
from_millis
(
100
))
.await
;
continue
;
};
let
Ok
(
component
)
=
namespace
.component
(
&
endpoint
.component
)
else
{
let
Ok
(
component
)
=
namespace
.component
(
&
endpoint
_id
.component
)
else
{
tracing
::
debug!
(
"Component not available yet, retrying..."
);
tokio
::
time
::
sleep
(
Duration
::
from_millis
(
100
))
.await
;
continue
;
...
...
@@ -509,13 +509,13 @@ impl AsyncEngine<SingleIn<PreprocessedRequest>, ManyOut<Annotated<LLMEngineOutpu
/// Create a mocker engine as ExecutionContext
pub
async
fn
make_mocker_engine
(
distributed_runtime
:
DistributedRuntime
,
endpoint
:
dynamo_runtime
::
protocols
::
Endpoint
,
endpoint
_id
:
dynamo_runtime
::
protocols
::
Endpoint
Id
,
args
:
MockEngineArgs
,
)
->
Result
<
crate
::
backend
::
ExecutionContext
,
Error
>
{
// Create the mocker engine
tracing
::
info!
(
"Creating mocker engine with config: {args:?}"
);
let
annotated_engine
=
AnnotatedMockEngine
::
new
(
MockVllmEngine
::
new
(
args
),
distributed_runtime
,
endpoint
);
AnnotatedMockEngine
::
new
(
MockVllmEngine
::
new
(
args
),
distributed_runtime
,
endpoint
_id
);
Ok
(
Arc
::
new
(
annotated_engine
))
}
...
...
lib/llm/src/mocker/scheduler.rs
View file @
6a358f7c
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Asynchronous Scheduler for LLM Request Management
//!
...
...
@@ -207,7 +195,7 @@ impl SchedulerState {
/// Remove a UUID and its associated Request from collections.
fn
complete
(
&
mut
self
,
uuid
:
&
Uuid
)
{
tracing
::
debug
!
(
"Request {} will complete"
,
uuid
);
tracing
::
trace
!
(
"Request {
uuid
} will complete"
);
self
.decode
.remove
(
uuid
);
self
.requests
.remove
(
uuid
);
self
.prefill_costs
.remove
(
uuid
);
...
...
lib/llm/src/protocols/common/llm_backend.rs
View file @
6a358f7c
...
...
@@ -192,10 +192,5 @@ mod tests {
assert_eq!
(
format!
(
"{}"
,
output
.err
()
.unwrap
()),
"Test error"
);
assert
!
(
!
output
.is_ok
());
assert
!
(
output
.is_err
());
let
output
=
LLMEngineOutput
::
from_err
(
anyhow
::
Error
::
msg
(
"Test error 2"
)
.into
());
assert_eq!
(
format!
(
"{}"
,
output
.err
()
.unwrap
()),
"Test error 2"
);
assert
!
(
!
output
.is_ok
());
assert
!
(
output
.is_err
());
}
}
lib/runtime/src/component.rs
View file @
6a358f7c
...
...
@@ -47,7 +47,7 @@ use super::{
};
use
crate
::
pipeline
::
network
::{
ingress
::
push_endpoint
::
PushEndpoint
,
PushWorkHandler
};
use
crate
::
protocols
::
Endpoint
as
EndpointId
;
use
crate
::
protocols
::
EndpointId
;
use
crate
::
service
::
ComponentNatsServerPrometheusMetrics
;
use
async_nats
::{
rustls
::
quic
,
...
...
lib/runtime/src/protocols.rs
View file @
6a358f7c
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use
serde
::{
Deserialize
,
Serialize
};
use
std
::
str
::
FromStr
;
use
crate
::
pipeline
::
PipelineError
;
pub
mod
annotated
;
pub
mod
maybe_error
;
...
...
@@ -43,22 +29,21 @@ pub struct Component {
/// Represents an endpoint with a namespace, component, and name.
///
/// An
`
Endpoint
`
is defined by a three-part string separated by `/` or a '.':
/// An
[
Endpoint
Id]
is defined by a three-part string separated by `/` or a '.':
/// - **namespace**
/// - **component**
/// - **name**
///
/// Example format: `"namespace/component/endpoint"`
///
/// TODO: There is also an Endpoint in runtime/src/component.rs
#[derive(Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq)]
pub
struct
Endpoint
{
pub
struct
Endpoint
Id
{
pub
namespace
:
String
,
pub
component
:
String
,
pub
name
:
String
,
}
impl
PartialEq
<
Vec
<&
str
>>
for
Endpoint
{
impl
PartialEq
<
Vec
<&
str
>>
for
Endpoint
Id
{
fn
eq
(
&
self
,
other
:
&
Vec
<&
str
>
)
->
bool
{
if
other
.len
()
!=
3
{
return
false
;
...
...
@@ -68,15 +53,27 @@ impl PartialEq<Vec<&str>> for Endpoint {
}
}
impl
PartialEq
<
Endpoint
>
for
Vec
<&
str
>
{
fn
eq
(
&
self
,
other
:
&
Endpoint
)
->
bool
{
impl
PartialEq
<
[
&
str
;
3
]
>
for
EndpointId
{
fn
eq
(
&
self
,
other
:
&
[
&
str
;
3
])
->
bool
{
self
.namespace
==
other
[
0
]
&&
self
.component
==
other
[
1
]
&&
self
.name
==
other
[
2
]
}
}
impl
PartialEq
<
EndpointId
>
for
[
&
str
;
3
]
{
fn
eq
(
&
self
,
other
:
&
EndpointId
)
->
bool
{
other
==
self
}
}
impl
PartialEq
<
EndpointId
>
for
Vec
<&
str
>
{
fn
eq
(
&
self
,
other
:
&
EndpointId
)
->
bool
{
other
==
self
}
}
impl
Default
for
Endpoint
{
impl
Default
for
Endpoint
Id
{
fn
default
()
->
Self
{
Endpoint
{
Endpoint
Id
{
namespace
:
DEFAULT_NAMESPACE
.to_string
(),
component
:
DEFAULT_COMPONENT
.to_string
(),
name
:
DEFAULT_ENDPOINT
.to_string
(),
...
...
@@ -84,8 +81,8 @@ impl Default for Endpoint {
}
}
impl
From
<&
str
>
for
Endpoint
{
/// Creates an
`
Endpoint
`
from a string.
impl
From
<&
str
>
for
Endpoint
Id
{
/// Creates an
[
Endpoint
Id]
from a string.
///
/// # Arguments
/// - `path`: A string in the format `"namespace/component/endpoint"`.
...
...
@@ -95,60 +92,86 @@ impl From<&str> for Endpoint {
/// Default values are used for missing parts.
///
/// # Examples:
/// - "component" -> ["DEFAULT_N
S
", "component", "DEFAULT_E"]
/// - "namespace.component" -> ["namespace", "component", "DEFAULT_E"]
/// - "component" -> ["DEFAULT_N
AMESPACE
", "component", "DEFAULT_E
NDPOINT
"]
/// - "namespace.component" -> ["namespace", "component", "DEFAULT_E
NDPOINT
"]
/// - "namespace.component.endpoint" -> ["namespace", "component", "endpoint"]
/// - "namespace/component" -> ["namespace", "component", "DEFAULT_E"]
/// - "namespace/component" -> ["namespace", "component", "DEFAULT_E
NDPOINT
"]
/// - "namespace.component.endpoint.other.parts" -> ["namespace", "component", "endpoint_other_parts"]
///
/// # Examples
/// ```
ignore
/// use dynamo_runtime:protocols::Endpoint;
/// ```
/// use dynamo_runtime:
:
protocols::Endpoint
Id
;
///
/// let endpoint = Endpoint::from("namespace/component/endpoint");
/// let endpoint = Endpoint
Id
::from("namespace/component/endpoint");
/// assert_eq!(endpoint.namespace, "namespace");
/// assert_eq!(endpoint.component, "component");
/// assert_eq!(endpoint.name, "endpoint");
/// ```
fn
from
(
input
:
&
str
)
->
Self
{
let
mut
result
=
Endpoint
::
default
(
);
fn
from
(
s
:
&
str
)
->
Self
{
let
input
=
s
.strip_prefix
(
ENDPOINT_SCHEME
)
.unwrap_or
(
s
);
// Split the input string on either '.' or '/'
let
elements
:
Vec
<&
str
>
=
input
let
mut
parts
=
input
.trim_matches
([
' '
,
'/'
,
'.'
])
.split
([
'.'
,
'/'
])
.filter
(|
x
|
!
x
.is_empty
())
.collect
();
match
elements
.len
()
{
0
=>
{}
1
=>
{
result
.component
=
elements
[
0
]
.to_string
();
.filter
(|
x
|
!
x
.is_empty
());
// Extract the first three potential components.
let
p1
=
parts
.next
();
let
p2
=
parts
.next
();
let
p3
=
parts
.next
();
let
namespace
;
let
component
;
let
name
;
match
(
p1
,
p2
,
p3
)
{
(
None
,
_
,
_
)
=>
{
// 0 elements: all fields remain empty.
// Should this be an error?
namespace
=
DEFAULT_NAMESPACE
.to_string
();
component
=
DEFAULT_COMPONENT
.to_string
();
name
=
DEFAULT_ENDPOINT
.to_string
();
}
(
Some
(
c
),
None
,
_
)
=>
{
namespace
=
DEFAULT_NAMESPACE
.to_string
();
component
=
c
.to_string
();
name
=
DEFAULT_ENDPOINT
.to_string
();
}
2
=>
{
result
.namespace
=
elements
[
0
]
.to_string
();
result
.component
=
elements
[
1
]
.to_string
();
(
Some
(
ns
),
Some
(
c
),
None
)
=>
{
// 2 elements: namespace, component
namespace
=
ns
.to_string
();
component
=
c
.to_string
();
name
=
DEFAULT_ENDPOINT
.to_string
();
}
3
=>
{
result
.namespace
=
elements
[
0
]
.to_string
();
result
.component
=
elements
[
1
]
.to_string
();
result
.name
=
elements
[
2
]
.to_string
();
(
Some
(
ns
),
Some
(
c
),
Some
(
ep
))
=>
{
namespace
=
ns
.to_string
();
component
=
c
.to_string
();
// For the 'name' field, we need to handle 'n' and any remaining parts.
// Instead of collecting into a Vec and then joining, we can build the string directly.
let
mut
endpoint_buf
=
String
::
from
(
ep
);
// Start with the third part
for
part
in
parts
{
// 'parts' iterator continues from where p3 left off
endpoint_buf
.push
(
'_'
);
endpoint_buf
.push_str
(
part
);
}
x
if
x
>
3
=>
{
result
.namespace
=
elements
[
0
]
.to_string
();
result
.component
=
elements
[
1
]
.to_string
();
result
.name
=
elements
[
2
..
]
.join
(
"_"
);
name
=
endpoint_buf
;
}
_
=>
unreachable!
(),
}
result
EndpointId
{
namespace
,
component
,
name
,
}
}
}
impl
FromStr
for
Endpoint
{
type
Err
=
PipelineError
;
impl
FromStr
for
Endpoint
Id
{
type
Err
=
core
::
convert
::
Infallible
;
/// Parses an `Endpoint` from a string using the standard Rust `.parse::<T>()` pattern.
/// Parses an `Endpoint
Id
` from a string using the standard Rust `.parse::<T>()` pattern.
///
/// This is implemented in terms of [`From<&str>`].
///
...
...
@@ -156,25 +179,24 @@ impl FromStr for Endpoint {
/// Does not fail
///
/// # Examples
/// ```
ignore
/// ```
/// use std::str::FromStr;
/// use dynamo_runtime:protocols::Endpoint;
/// use dynamo_runtime:
:
protocols::Endpoint
Id
;
///
/// let endpoint: Endpoint = "namespace/component/endpoint".parse().unwrap();
/// let endpoint: Endpoint
Id
= "namespace/component/endpoint".parse().unwrap();
/// assert_eq!(endpoint.namespace, "namespace");
/// assert_eq!(endpoint.component, "component");
/// assert_eq!(endpoint.name, "endpoint");
/// let endpoint: Endpoint = "dyn://namespace/component/endpoint".parse().unwrap();
/// let endpoint: Endpoint
Id
= "dyn://namespace/component/endpoint".parse().unwrap();
/// // same as above
/// assert_eq!(endpoint.name, "endpoint");
/// ```
fn
from_str
(
s
:
&
str
)
->
Result
<
Self
,
Self
::
Err
>
{
let
cleaned
=
s
.strip_prefix
(
ENDPOINT_SCHEME
)
.unwrap_or
(
s
);
Ok
(
Endpoint
::
from
(
cleaned
))
Ok
(
EndpointId
::
from
(
s
))
}
}
impl
Endpoint
{
impl
Endpoint
Id
{
/// As a String like dyn://dynamo.internal.worker
pub
fn
as_url
(
&
self
)
->
String
{
format!
(
...
...
@@ -193,7 +215,7 @@ mod tests {
#[test]
fn
test_valid_endpoint_from
()
{
let
input
=
"namespace1/component1/endpoint1"
;
let
endpoint
=
Endpoint
::
from
(
input
);
let
endpoint
=
Endpoint
Id
::
from
(
input
);
assert_eq!
(
endpoint
.namespace
,
"namespace1"
);
assert_eq!
(
endpoint
.component
,
"component1"
);
...
...
@@ -203,7 +225,7 @@ mod tests {
#[test]
fn
test_valid_endpoint_from_str
()
{
let
input
=
"namespace2/component2/endpoint2"
;
let
endpoint
=
Endpoint
::
from_str
(
input
)
.unwrap
();
let
endpoint
=
Endpoint
Id
::
from_str
(
input
)
.unwrap
();
assert_eq!
(
endpoint
.namespace
,
"namespace2"
);
assert_eq!
(
endpoint
.component
,
"component2"
);
...
...
@@ -213,7 +235,7 @@ mod tests {
#[test]
fn
test_valid_endpoint_parse
()
{
let
input
=
"namespace3/component3/endpoint3"
;
let
endpoint
:
Endpoint
=
input
.parse
()
.unwrap
();
let
endpoint
:
Endpoint
Id
=
input
.parse
()
.unwrap
();
assert_eq!
(
endpoint
.namespace
,
"namespace3"
);
assert_eq!
(
endpoint
.component
,
"component3"
);
...
...
@@ -222,7 +244,7 @@ mod tests {
#[test]
fn
test_endpoint_from
()
{
let
result
=
Endpoint
::
from
(
"component"
);
let
result
=
Endpoint
Id
::
from
(
"component"
);
assert_eq!
(
result
,
vec!
[
DEFAULT_NAMESPACE
,
"component"
,
DEFAULT_ENDPOINT
]
...
...
@@ -231,19 +253,19 @@ mod tests {
#[test]
fn
test_namespace_component_endpoint
()
{
let
result
=
Endpoint
::
from
(
"namespace.component.endpoint"
);
let
result
=
Endpoint
Id
::
from
(
"namespace.component.endpoint"
);
assert_eq!
(
result
,
vec!
[
"namespace"
,
"component"
,
"endpoint"
]);
}
#[test]
fn
test_forward_slash_separator
()
{
let
result
=
Endpoint
::
from
(
"namespace/component"
);
let
result
=
Endpoint
Id
::
from
(
"namespace/component"
);
assert_eq!
(
result
,
vec!
[
"namespace"
,
"component"
,
DEFAULT_ENDPOINT
]);
}
#[test]
fn
test_multiple_parts
()
{
let
result
=
Endpoint
::
from
(
"namespace.component.endpoint.other.parts"
);
let
result
=
Endpoint
Id
::
from
(
"namespace.component.endpoint.other.parts"
);
assert_eq!
(
result
,
vec!
[
"namespace"
,
"component"
,
"endpoint_other_parts"
]
...
...
@@ -253,23 +275,31 @@ mod tests {
#[test]
fn
test_mixed_separators
()
{
// Do it the .into way for variety and documentation
let
result
:
Endpoint
=
"namespace/component.endpoint"
.into
();
let
result
:
Endpoint
Id
=
"namespace/component.endpoint"
.into
();
assert_eq!
(
result
,
vec!
[
"namespace"
,
"component"
,
"endpoint"
]);
}
#[test]
fn
test_empty_string
()
{
let
result
=
Endpoint
::
from
(
""
);
let
result
=
Endpoint
Id
::
from
(
""
);
assert_eq!
(
result
,
vec!
[
DEFAULT_NAMESPACE
,
DEFAULT_COMPONENT
,
DEFAULT_ENDPOINT
]
);
// White space is equivalent to an empty string
let
result
=
Endpoint
::
from
(
" "
);
let
result
=
Endpoint
Id
::
from
(
" "
);
assert_eq!
(
result
,
vec!
[
DEFAULT_NAMESPACE
,
DEFAULT_COMPONENT
,
DEFAULT_ENDPOINT
]
);
}
#[test]
fn
test_parse_with_scheme_and_url_roundtrip
()
{
let
input
=
"dyn://ns/cp/ep"
;
let
endpoint
:
EndpointId
=
input
.parse
()
.unwrap
();
assert_eq!
(
endpoint
,
vec!
[
"ns"
,
"cp"
,
"ep"
]);
assert_eq!
(
endpoint
.as_url
(),
"dyn://ns.cp.ep"
);
}
}
lib/runtime/src/protocols/annotated.rs
View file @
6a358f7c
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use
super
::
*
;
use
crate
::{
error
,
Result
};
...
...
@@ -199,17 +187,13 @@ mod tests {
let
annotated
=
Annotated
::
from_data
(
"Test data"
.to_string
());
assert
!
(
annotated
.err
()
.is_none
());
assert
!
(
annotated
.is_ok
());
assert
!
(
!
annotated
.is_err
());
let
annotated
=
Annotated
::
<
String
>
::
from_error
(
"Test error 2"
.to_string
());
assert_eq!
(
format!
(
"{}"
,
annotated
.err
()
.unwrap
()),
"Test error 2"
);
assert
!
(
!
annotated
.is_ok
());
assert
!
(
annotated
.is_err
());
let
annotated
=
Annotated
::
<
String
>
::
from_err
(
anyhow
::
Error
::
msg
(
"Test error 3"
.to_string
())
.into
());
assert_eq!
(
format!
(
"{}"
,
annotated
.err
()
.unwrap
()),
"Test error 3"
);
assert
!
(
!
annotated
.is_ok
());
assert
!
(
annotated
.is_err
());
}
}
lib/runtime/src/storage/key_value_store/nats.rs
View file @
6a358f7c
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use
std
::{
collections
::
HashMap
,
pin
::
Pin
,
time
::
Duration
};
use
crate
::{
protocols
::
Endpoint
,
slug
::
Slug
,
transports
::
nats
::
Client
};
use
crate
::{
protocols
::
Endpoint
Id
,
slug
::
Slug
,
transports
::
nats
::
Client
};
use
async_trait
::
async_trait
;
use
futures
::
StreamExt
;
...
...
@@ -24,7 +12,7 @@ use super::{KeyValueBucket, KeyValueStore, StorageError, StorageOutcome};
#[derive(Clone)]
pub
struct
NATSStorage
{
client
:
Client
,
endpoint
:
Endpoint
,
endpoint
:
Endpoint
Id
,
}
pub
struct
NATSBucket
{
...
...
@@ -58,7 +46,7 @@ impl KeyValueStore for NATSStorage {
}
impl
NATSStorage
{
pub
fn
new
(
client
:
Client
,
endpoint
:
Endpoint
)
->
Self
{
pub
fn
new
(
client
:
Client
,
endpoint
:
Endpoint
Id
)
->
Self
{
NATSStorage
{
client
,
endpoint
}
}
...
...
@@ -91,8 +79,10 @@ impl NATSStorage {
},
)
.await
;
let
nats_store
=
create_result
.map_err
(|
err
|
StorageError
::
KeyValueError
(
err
.to_string
(),
bucket_name
.clone
()))
?
;
tracing
::
debug!
(
"Created bucket {bucket_name}"
);
create_result
.map_err
(|
err
|
StorageError
::
KeyValueError
(
err
.to_string
(),
bucket_name
)
)
Ok
(
nats_store
)
}
async
fn
get_key_value
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment