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
"lib/bindings/vscode:/vscode.git/clone" did not exist on "ba9a8a9fb6f33a65a1745d096d83d7d789048357"
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