-
Notifications
You must be signed in to change notification settings - Fork 0
basic app
Version: 0.1.7
Last modified date: 2026-02-17
This example shows how to build a simple DMSC application, including application configuration, running, and basic functionality usage.
This example will create a basic DMSC application that implements the following features:
- Load configuration files
- Enable logging
- Enable observability
- Output a startup log
- Rust 1.65+
- Cargo 1.65+
- Basic Rust programming knowledge
cargo new dms-basic-example
cd dms-basic-exampleAdd the following dependencies to your Cargo.toml file:
[dependencies]
dmsc = { path = "../dmsc" }
tokio = { version = "1.0", features = ["full"] }Create a config.yaml file in the project root:
service:
name: "dms-basic-example"
version: "1.0.0"
logging:
level: "info"
format: "json"
file_enabled: false
console_enabled: true
observability:
metrics_enabled: true
tracing_enabled: true
prometheus_port: 9090Replace the content of src/main.rs with the following:
use dmsc::prelude::*;
#[tokio::main]
async fn main() -> DMSCResult<()> {
// Build service runtime
let app = DMSCAppBuilder::new()
.with_config("config.yaml")?
.with_logging(DMSCLogConfig::default())
.with_observability(DMSCObservabilityConfig::default())
.build()?;
// Run business logic
app.run(|ctx: &DMSCServiceContext| async move {
// Get service name and version
let service_name = ctx.config().config().get_str("service.name").unwrap_or("unknown");
let service_version = ctx.config().config().get_str("service.version").unwrap_or("unknown");
// Output startup log
ctx.logger().info(
"service",
&format!("{} v{} started successfully", service_name, service_version)
)?;
// Output configuration info
let log_level = ctx.config().config().get_str("logging.level").unwrap_or("info");
ctx.logger().info(
"config",
&format!("Logging level: {}", log_level)
)?;
// Wait 3 seconds to simulate business running
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
ctx.logger().info("service", "Service finished successfully")?;
Ok(())
}).await
}use dmsc::prelude::*;This line imports the most commonly used types and traits from DMSC, simplifying code writing. The prelude module contains core components needed for building DMSC applications.
#[tokio::main]
async fn main() -> DMSCResult<()> {
// Code...
}-
#[tokio::main]: Converts the main function into an async function and executes it using the Tokio runtime -
async fn main(): Defines an asynchronous main function -
-> DMSCResult<()>: Returns DMSC result type for error handling
let app = DMSCAppBuilder::new()
.with_config("config.yaml")?
.with_logging(DMSCLogConfig::default())?
.with_observability(DMSCObservabilityConfig::default())?
.build()?;-
DMSCAppBuilder::new(): Creates a new application builder -
.with_config("config.yaml")?: Loads the configuration file -
.with_logging(DMSCLogConfig::default())?: Enables logging with default configuration -
.with_observability(DMSCObservabilityConfig::default())?: Enables observability with default configuration -
.build()?: Builds the application runtime
app.run(|ctx: &DMSCServiceContext| async move {
// Business logic
}).await-
app.run(): Starts the application runtime -
|ctx: &DMSCServiceContext|: Closure parameter that receives the service context -
async move: Async closure that allows usingawaitinside the closure
let service_name = ctx.config().config().get_str("service.name").unwrap_or("unknown");
let service_version = ctx.config().config().get_str("service.version").unwrap_or("unknown");
ctx.logger().info(
"service",
&format!("{} v{} started successfully", service_name, service_version)
)?;-
ctx.config().config().get_str(): Gets a value from the configuration -
ctx.logger().info(): Records an info-level log -
?: Propagates errors
cargo buildcargo runAfter running the example, you should see output similar to the following:
{
"timestamp": "2025-12-12T15:30:00Z",
"level": "info",
"module": "service",
"message": "dms-basic-example v1.0.0 started successfully",
"trace_id": "abc123",
"span_id": "def456"
}
{
"timestamp": "2025-12-12T15:30:00Z",
"level": "info",
"module": "config",
"message": "Logging level: info",
"trace_id": "abc123",
"span_id": "def456"
}
{
"timestamp": "2025-12-12T15:30:03Z",
"level": "info",
"module": "service",
"message": "Service finished successfully",
"trace_id": "abc123",
"span_id": "def456"
}Note: Cache functionality needs to be separately configured and enabled through the module system. Cache module is accessed via DMSCCacheModule.
// Add cache module
let cache_module = DMSCCacheModule::new(DMSCCacheConfig::default());
let app = DMSCAppBuilder::new()
.with_config("config.yaml")?
.with_logging(DMSCLogConfig::default())?
.with_dms_module(Box::new(cache_module))?
.build()?;
// Use cache in business logic
app.run(|ctx: &DMSCServiceContext| async move {
// Get cache module
let cache = ctx.module::<DMSCCacheModule>().await?;
let cache_manager = cache.cache_manager();
// Set cache
cache_manager.set("key", "value", Some(3600)).await?;
// Get cache
let value: Option<String> = cache_manager.get("key").await?;
ctx.logger().info("cache", &format!("Cached value: {:?}", value))?;
Ok(())
}).awaitNote: Queue functionality needs to be separately configured and enabled through the module system. Queue module is accessed via DMSCQueueModule.
// Add queue module
let queue_module = DMSCQueueModule::new(DMSCQueueConfig::default());
let app = DMSCAppBuilder::new()
.with_config("config.yaml")?
.with_logging(DMSCLogConfig::default())?
.with_dms_module(Box::new(queue_module))?
.build()?;
// Use queue in business logic
app.run(|ctx: &DMSCServiceContext| async move {
// Get queue module
let queue = ctx.module::<DMSCQueueModule>().await?;
let queue_manager = queue.queue_manager();
// Get or create queue
let queue = queue_manager.create_queue("task_queue").await?;
// Send message
queue.publish(&DMSCQueueMessage::new("task-123", json!({
"task_type": "data_processing",
"priority": 1,
}))).await?;
ctx.logger().info("queue", "Task message sent to queue")?;
Ok(())
}).await// Use file system in business logic
app.run(|ctx: &DMSCServiceContext| async move {
// Write to file
ctx.fs().atomic_write_text("data/config.json", r#"{"setting": "value"}"#)?;
// Read from file
let content = ctx.fs().read_text("data/config.json")?;
ctx.logger().info("fs", &format!("File content: {}", content))?;
// Check if file exists
let exists = ctx.fs().exists("data/config.json");
ctx.logger().info("fs", &format!("File exists: {}", exists))?;
Ok(())
}).await// Define custom module
struct MyCustomModule {
name: String,
}
impl MyCustomModule {
async fn process_data(&self, data: &str) -> DMSCResult<String> {
// Custom processing logic
Ok(format!("Processed by {}: {}", self.name, data))
}
}
// Add custom module when building the application
let custom_module = MyCustomModule {
name: "MyProcessor".to_string(),
};
let app = DMSCAppBuilder::new()
.with_config("config.yaml")?
.with_logging(DMSCLogConfig::default())?
.with_module(custom_module)?
.build()?;
// Use custom module in business logic
app.run(|ctx: &DMSCServiceContext| async move {
// Get custom module
let processor = ctx.module::<MyCustomModule>()?;
// Use custom functionality
let result = processor.process_data("sample data").await?;
ctx.logger().info("custom", &format!("Processing result: {}", result))?;
Ok(())
}).await-
Start Simple: Create a basic application first, ensure it runs correctly, then gradually add other modules
-
Configure Logging Appropriately: Adjust log levels based on environment, use
debugfor development andinfoorwarnfor production -
Use Configuration Files: Place configuration information in files, avoiding hardcoding, for easier deployment across different environments
-
Handle Errors Properly: Use the
?operator to propagate errors, ensuring errors are correctly handled -
Design Modularly: Encapsulate business logic in functions or modules to keep code clean
-
Test Driven Development: Write unit tests and integration tests to ensure code quality
This example demonstrates how to build a simple DMSC application, including:
- Project creation and dependency addition
- Configuration file writing
- Application building and running
- Basic functionality usage
Through this example, you should have understood the basic structure and usage of DMSC applications. You can further explore other features of DMSC based on this foundation.
- README: Usage examples overview, providing quick navigation to all usage examples
- basic-app: Basic application example, learn how to create and run your first DMSC application
- authentication: Authentication example, learn JWT, OAuth2, and RBAC authentication and authorization
- caching: Caching example, understand how to use the cache module to improve application performance
- database: Database example, learn database connection and query operations
- grpc: gRPC examples, implement high-performance RPC calls
- websocket: WebSocket examples, implement real-time bidirectional communication
- observability: Observability example, monitor application performance and health status
- validation: Validation example, data validation and sanitization operations