Skip to content

Commit 5309043

Browse files
committed
Merge branch 'features/cache' of github.com:thuan2172001/rust-api-server into HEAD
2 parents fe71498 + 10d96b3 commit 5309043

File tree

17 files changed

+910
-349
lines changed

17 files changed

+910
-349
lines changed

Cargo.lock

Lines changed: 767 additions & 291 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Dockerfile

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ COPY . .
2020
RUN cargo build --release --all
2121
RUN mv target/${CARGO_BUILD_TARGET}/release /out
2222

23-
FROM scratch AS prod
23+
FROM alpine AS dev
2424
WORKDIR /user
2525
COPY src/public/config/00-default.toml 00-default.toml
2626
COPY --from=builder /out/cli /usr/local/bin/rust-server
27-
ENTRYPOINT ["/usr/local/bin/rust-server", "--config-path=*.toml"]
27+
COPY --from=bunyan /root/.cargo/bin/bunyan /usr/local/bin/
28+
ENTRYPOINT ["/bin/sh"]
29+
CMD ["-c", "/usr/local/bin/rust-server --config-path=*.toml | bunyan"]
2830

2931
FROM alpine AS dev
3032
WORKDIR /user
@@ -33,3 +35,15 @@ COPY --from=builder /out/cli /usr/local/bin/rust-server
3335
COPY --from=bunyan /root/.cargo/bin/bunyan /usr/local/bin/
3436
ENTRYPOINT ["/bin/sh"]
3537
CMD ["-c", "/usr/local/bin/rust-server --config-path=*.toml | bunyan"]
38+
39+
FROM scratch AS prod
40+
WORKDIR /user
41+
COPY src/public/config/00-default.toml 00-default.toml
42+
COPY --from=builder /out/cli /usr/local/bin/rust-server
43+
ENTRYPOINT ["/usr/local/bin/rust-server", "--config-path=*.toml"]
44+
45+
FROM scratch AS prod
46+
WORKDIR /user
47+
COPY src/public/config/00-default.toml 00-default.toml
48+
COPY --from=builder /out/cli /usr/local/bin/rust-server
49+
ENTRYPOINT ["/usr/local/bin/rust-server", "--config-path=*.toml"]

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ build:
3030
BUILD_RELEASE=$(shell git describe --tags --abbrev=0)
3131
BUILDKIT_PROGRESS=plain
3232
DOCKER_BUILDKIT=1
33-
docker build --ssh default -t $(PKG_NAME):$(BUILD_VERSION) --target=prod .
33+
docker build -t $(PKG_NAME):$(BUILD_VERSION) --target=public-prod .
34+
docker build -t $(PKG_NAME):$(BUILD_VERSION) --target=gpt-prod .
3435

3536
build-dev:
36-
BUILDKIT_PROGRESS=plain DOCKER_BUILDKIT=1 docker build --ssh default -t $(PKG_NAME):$(BUILD_VERSION) --target=dev .
37+
BUILDKIT_PROGRESS=plain DOCKER_BUILDKIT=1 docker build -t $(PKG_NAME):$(BUILD_VERSION) --target=public-dev .
38+
BUILDKIT_PROGRESS=plain DOCKER_BUILDKIT=1 docker build -t $(PKG_NAME):$(BUILD_VERSION) --target=gpt-dev .
3739

3840
profiling-public:
3941
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --root -- -c ./src/public/config/* -c ./deploy/local/custom.toml

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,17 @@ options:
9595

9696
Hierarchical child config via env, separated by using `__`. Specify list values by using `,` separator
9797

98-
| ENV | DEFAULT VALUE | NOTE |
99-
| ------------------------------------------------------------------------ | ------------- | --------- |
100-
| [RUST_LOG](https://docs.rs/env_logger/latest/env_logger/) > LOG\_\_LEVEL | "INFO" | Log level |
101-
| SERVER\_\_URL | | |
102-
| SERVER\_\_PORT | | |
103-
| SERVICE_NAME | | |
104-
| EXPORTER_ENDPOINT | | |
105-
| DB\_\_PG\_\_URL | "LOCALHOST" | |
106-
| DB\_\_PG\_\_MAX_SIZE | "5432" | |
107-
| REDIS\_\_HOST | "LOCALHOST" | |
108-
| REDIS\_\_PORT | "6379" | |
98+
| ENV | DEFAULT VALUE | NOTE |
99+
|------------------------------------------------------------------------|---------------|-----------|
100+
| [RUST_LOG](https://docs.rs/env_logger/latest/env_logger/) > LOG__LEVEL | "INFO" | Log level |
101+
| SERVER\_\_URL | | |
102+
| SERVER\_\_PORT | | |
103+
| SERVICE_NAME | | |
104+
| EXPORTER_ENDPOINT | | |
105+
| DB\_\_PG\_\_URL | "localhost" | |
106+
| DB\_\_PG\_\_MAX_SIZE | 5432 | |
107+
| REDIS\_\_HOST | "localhost" | |
108+
| REDIS\_\_PORT | 6379 | |
109109

110110
Make sure to set these environment variables according to your needs before running the server.
111111

File renamed without changes.

deploy/docker/docker-compose.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ services:
4848
ports:
4949
- "8888:8888"
5050
volumes:
51-
- ./01_public_custom.toml:/user/01-custom.toml:ro
51+
- ./01_public_custom.toml:/user/01_custom.toml:ro
5252
gpt_answer_server:
5353
image: gpt_answer_server
5454
build:
@@ -57,7 +57,7 @@ services:
5757
ports:
5858
- "9999:9999"
5959
volumes:
60-
- ./01_gpt_answer_server_custom.toml.toml:/user/01-custom.toml:ro
60+
- ./01_gpt_answer_server_custom.toml.toml:/user/01_custom.toml:ro
6161
volumes:
6262
postgres:
6363
redis:

src/adapter/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,27 @@ version = "2.1.0"
2525
version = "0.1.80"
2626

2727
[dependencies.deadpool-diesel]
28-
version = "0.6.0"
28+
version = "0.6.1"
2929
features = ["postgres", "serde"]
3030

3131
[dependencies.diesel]
32-
version = "2.1.4"
32+
version = "2.1.6"
3333
features = ["postgres", "postgres_backend", "uuid"]
3434

3535
[dependencies.serde]
3636
version = "1.0"
3737
features = ["derive"]
3838

3939
[dependencies.testcontainers-modules]
40-
version = "0.3.7"
40+
version = "0.4.3"
4141
features = ["postgres", "redis"]
4242

4343
[dependencies.tokio]
4444
version = "1.36.0"
4545
features = ["full"]
4646

4747
[dependencies.anyhow]
48-
version = "1.0.82"
48+
version = "1.0.83"
4949

5050
[dependencies.tonic]
5151
version = "0.11.0"

src/adapter/src/repositories/redis/cache.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ impl RedisCache {
1515
///
1616
/// # Arguments
1717
///
18-
/// * redis_host: Hostname or IP address of the Redis server.
19-
/// * redis_port: Port number of the Redis server.
18+
/// * `redis_host`: Hostname or IP address of the Redis server.
19+
/// * `redis_port`: Port number of the Redis server.
2020
///
2121
/// # Returns
2222
///
23-
/// Returns a Result containing the initialized RedisCache instance.
23+
/// Returns a `Result` containing the initialized `RedisCache` instance.
2424
pub async fn new(redis_host: &str, redis_port: u16) -> Result<Self, CoreError> {
2525
client::paired_connect(redis_host, redis_port)
2626
.await
@@ -35,7 +35,7 @@ impl CachePort for RedisCache {
3535
///
3636
/// # Arguments
3737
///
38-
/// * key: The key of the value to retrieve.
38+
/// * `key`: The key of the value to retrieve.
3939
///
4040
/// # Returns
4141
///

src/adapter/src/repositories/repository_test.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ mod question_repository_tests {
88
Manager,
99
};
1010
use diesel_migrations::MigrationHarness;
11-
use testcontainers_modules::{postgres::Postgres, testcontainers::clients::Cli};
11+
use testcontainers_modules::postgres::Postgres;
12+
use testcontainers_modules::testcontainers::runners::AsyncRunner;
1213

1314
use rust_core::{
1415
entities::{
@@ -89,12 +90,11 @@ mod question_repository_tests {
8990
#[tokio::test]
9091
async fn question_postgres_repository_test() {
9192
// Set up a postgres database question port for testing
92-
let docker = Cli::default();
93-
let postgres_instance = docker.run(Postgres::default());
93+
let postgres_instance = Postgres::default().start().await;
9494

9595
let database_url = format!(
9696
"postgres://postgres:postgres@127.0.0.1:{}/postgres",
97-
postgres_instance.get_host_port_ipv4(5432)
97+
postgres_instance.get_host_port_ipv4(5432).await
9898
);
9999
let database_config = DatabaseConfig {
100100
url: database_url.clone(),
@@ -130,11 +130,15 @@ mod question_repository_tests {
130130
mod cache_repository_tests {
131131
use std::time::Duration;
132132

133-
use crate::repositories::{in_memory::cache::InMemoryCache, redis::cache::RedisCache};
134-
use rust_core::ports::cache::CachePort;
135-
use testcontainers_modules::{redis::Redis, testcontainers::clients::Cli};
133+
use testcontainers_modules::redis::Redis;
134+
use testcontainers_modules::testcontainers::runners::AsyncRunner;
136135
use tokio::time::sleep;
137136

137+
use rust_core::common::errors::CoreError;
138+
use rust_core::ports::cache::CachePort;
139+
140+
use crate::repositories::{in_memory::cache::InMemoryCache, redis::cache::RedisCache};
141+
138142
async fn test_cache_operations<C: CachePort>(mut cache: C) {
139143
let test_key = "key1";
140144
let test_value = "value1";
@@ -155,22 +159,25 @@ mod cache_repository_tests {
155159

156160
// Verify that test_key" is deleted and cannot retrievable
157161
let get_result = cache.get(&test_key).await;
158-
assert!(get_result.is_err());
162+
assert!(matches!(get_result, Err(CoreError::NotFound)));
159163

160164
// Test deleting a non-existing key
161165
let del_result = cache.del("non_existing_key").await;
162-
assert!(del_result.is_err());
166+
assert!(matches!(del_result, Err(CoreError::NotFound)));
163167

164168
// Test set operation for test_key with limit expiration time
165169
let set_result = cache
166170
.set(&test_key, &test_value, Some(Duration::from_secs(1)))
167171
.await;
168172
assert!(set_result.is_ok());
169173

174+
let set_result = cache.get(&test_key).await;
175+
assert!(set_result.is_ok());
176+
170177
// Test get an expired key
171178
sleep(Duration::from_secs(1)).await;
172179
let get_result = cache.get(&test_key).await;
173-
assert!(get_result.is_err());
180+
assert!(matches!(get_result, Err(CoreError::NotFound)));
174181
}
175182

176183
#[tokio::test]
@@ -181,10 +188,9 @@ mod cache_repository_tests {
181188

182189
#[tokio::test]
183190
async fn test_redis_cache_operations() {
184-
let docker = Cli::default();
185-
let redis_cache = docker.run(Redis::default());
191+
let redis_instance = Redis::default().start().await;
186192
let host = "127.0.0.1";
187-
let port = redis_cache.get_host_port_ipv4(6379);
193+
let port = redis_instance.get_host_port_ipv4(6379).await;
188194
let cache = RedisCache::new(host, port).await.unwrap();
189195
test_cache_operations(cache).await;
190196
}

src/common/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ version = "0.15.0"
3434
features = ["tonic"]
3535

3636
[dependencies.opentelemetry-semantic-conventions]
37-
version = "0.14.0"
37+
version = "0.15.0"
3838

3939
[dependencies.opentelemetry_sdk]
4040
version = "0.22.1"
@@ -48,6 +48,9 @@ features = ["derive"]
4848
version = "0.3.18"
4949
features = ["env-filter"]
5050

51+
[dependencies.tokio]
52+
version = "1.37.0"
53+
5154
[dependencies.tonic]
5255
version = "0.11.0"
5356

src/common/src/kill_signals.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use tokio::signal;
2+
use tracing::info;
3+
4+
pub async fn wait_for_kill_signals() {
5+
let ctrl_c = async {
6+
signal::ctrl_c()
7+
.await
8+
.expect("Failed to install Ctrl+C handler");
9+
};
10+
11+
#[cfg(unix)]
12+
let terminate = async {
13+
signal::unix::signal(signal::unix::SignalKind::terminate())
14+
.expect("Failed to install signal handler")
15+
.recv()
16+
.await;
17+
};
18+
19+
#[cfg(not(unix))]
20+
let terminate = std::future::pending::<()>();
21+
22+
tokio::select! {
23+
_ = ctrl_c => {
24+
info!("Received ctrl_c!");
25+
},
26+
_ = terminate => {
27+
info!("Received terminate!");
28+
},
29+
}
30+
}

src/common/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod grpc;
2+
pub mod kill_signals;
23
pub mod loggers;
34
pub mod options;

src/core/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ version = "1.0"
2020
features = ["derive"]
2121

2222
[dependencies.thiserror]
23-
version = "1.0.57"
23+
version = "1.0.60"
2424

2525
[dependencies.anyhow]
26-
version = "1.0.82"
26+
version = "1.0.83"

src/gpt_answer_server/src/main.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@ use std::sync::Arc;
22

33
use clap::{Parser, Subcommand};
44
use opentelemetry::global;
5+
use tokio::sync::oneshot;
6+
use tokio::sync::oneshot::Receiver;
57
use tonic::transport::Server;
8+
use tracing::info;
69

710
use adapter::repositories::redis::cache::RedisCache;
811
use common::grpc::gpt_answer::gpt_answer::gpt_answer_service_server::GptAnswerServiceServer;
12+
use common::kill_signals;
913
use common::loggers::telemetry::init_telemetry;
1014
use common::options::parse_options;
1115
use gpt_answer_server::controllers::gpt_answer::GptAnswerServiceImpl;
1216
use gpt_answer_server::options::Options;
1317

14-
pub async fn serve(options: Options) {
18+
pub async fn serve(options: Options, rx: Receiver<()>) {
1519
let address = options.server_endpoint.parse().unwrap();
1620
println!("Starting GPT Answer server at {}", options.server_endpoint);
1721

@@ -23,7 +27,10 @@ pub async fn serve(options: Options) {
2327

2428
Server::builder()
2529
.add_service(GptAnswerServiceServer::new(gpt_answer_service))
26-
.serve(address)
30+
.serve_with_shutdown(address, async {
31+
rx.await.ok();
32+
info!("GRPC server shut down");
33+
})
2734
.await
2835
.unwrap();
2936
}
@@ -55,11 +62,17 @@ async fn main() {
5562
options.log.level.as_str(),
5663
);
5764

58-
let server = tokio::spawn(serve(options));
65+
let (tx, rx) = oneshot::channel();
66+
let server = tokio::spawn(serve(options, rx));
5967

60-
tokio::try_join!(server).expect("Failed to run servers");
68+
kill_signals::wait_for_kill_signals().await;
69+
70+
// Send the shutdown signal
71+
let _ = tx.send(());
72+
tokio::try_join!(server).expect("Failed to run server");
6173

6274
global::shutdown_tracer_provider();
75+
info!("Shutdown successfully!");
6376
}
6477

6578
/// GPT Answer GRPC server.

src/public/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,11 @@ version = "4.4.7"
8282
features = ["derive"]
8383

8484
[dependencies.deadpool-diesel]
85-
version = "0.6.0"
85+
version = "0.6.1"
8686
features = ["postgres", "serde"]
8787

8888
[dependencies.diesel]
89-
version = "2.1.0"
89+
version = "2.1.6"
9090
features = ["postgres", "postgres_backend", "uuid"]
9191

9292
[dependencies.openssl]
@@ -100,18 +100,18 @@ version = "1.0"
100100
features = ["derive"]
101101

102102
[dependencies.testcontainers-modules]
103-
version = "0.3.7"
103+
version = "0.4.3"
104104
features = ["postgres", "redis"]
105105

106106
[dependencies.tokio]
107107
version = "1.36.0"
108108
features = ["full"]
109109

110110
[dependencies.thiserror]
111-
version = "1.0.57"
111+
version = "1.0.60"
112112

113113
[dependencies.anyhow]
114-
version = "1.0.82"
114+
version = "1.0.83"
115115

116116
[lib]
117117
path = "src/lib.rs"

0 commit comments

Comments
 (0)