Skip to main content

jupiter/
lib.rs

1//! Jupiter is a library for providing high throughput ultra low latency services via the RESP
2//! protocol as defined by Redis.
3//!
4//! # Introduction
5//! **Jupiter** is a framework for wrapping **compute** or **memory intense** components to
6//! provide them as **high throughput** and **ultra low latency** services to
7//! applications built on managed runtimes like **node.js**, **Java**, **Ruby**.
8//!
9//! These managed runtimes are great for building sophisticated web applications but have limited
10//! capabilities when raw compute power or optimized memory utilization is required. This
11//! on the other hand is an area where **Rust** shines, as it permits to write low-level
12//! and highly optimized code which is still safe to run.
13//!
14//! Therefore all we need is a simple an efficient way of combining the best of both worlds.
15//! To minimize the overhead of communication, we use the [RESP Protocol](https://redis.io/topics/protocol)
16//! as defined by **Redis**. In contrast to HTTP this is way simpler to parse and handle while
17//! also supporting zero-copy operations. Another benefit is, that for nearly every platform
18//! there is already a Redis/RESP client available.
19//!
20//! # SIRIUS / Java
21//! We at [scireum](https://www.scireum.de) use **Jupiter** in conjunction with our open source
22//! Java framework [SIRIUS](https://github.com/scireum/sirius-kernel) to build web based
23//! applications.
24//!
25//! We use **Jupiter** as an LRU cache for intermediate search results and search metadata. We also
26//! store large parts of semi-constant masterdata (think of "all ZIP codes and street names in
27//! germany) there. Both of these frameworks are contributed to the open source community and can
28//! be either used in own applications or directly by running a
29//! [Jupiter IO](https://hub.docker.com/repository/docker/scireum/jupiter-io) instance.
30//!
31//! Our most central use of this framework lies in **Quasar** which sadly has to remain closed
32//! source. This application contains our complete text processing framework which runs everything
33//! from syntactical pre-processing to full morphological analysis steps in order to maintain our
34//! excellent search experience in our products.
35//!
36//! # Features
37//! * **Ultra fast non allocating parser for RESP queries** (as sent by redis-cli and redis clients).
38//!   The built-in server will use a single buffer per connection to read, parse and process queries.
39//!   To deliver a response, a single buffer is allocated to buffer the response to minimize the
40//!   number of required sys-calls to write a response on the wire.
41//! * **100% Async/Await** - the whole server builds upon [tokio](https://tokio.rs/) and async/await
42//!   primitives as provided by Rust. Also, all commands handlers are build as actors to simplify
43//!   concurrency correctness and to also minimize any synchronization overheads.
44//! * **Reload-aware config facility** which permits to update the configuration during operation.
45//!   Therefore, no restart is ever required, even when changing the IP binding or port. This is
46//!   kind of important for an in-memory application which might have an expensive startup time.
47//! * **Build in management commands**. The *core* module provides a set of management commands to
48//!   monitor and inspect the state of the system.
49//! * **Simple and well documented code base**. After all, Jupiter isn't a large framework at all.
50//!   This permits every user to browse and understand its source code and when to expect from the
51//!   system. Also, this is due to the fact that Jupiter stands on the shoulders of giants
52//!   (especially [tokio](https://tokio.rs/)).
53//!
54//! # Modules
55//! * **LRU-Cache**: An size constraint cache with an intelligent refresh strategy which can be used
56//!   to maintain low latency response times by employing a coordinated asynchronous cache update
57//!   pattern (see `LRU.XGET` or the module documentation of [crate::lru::cache]).
58//! * **InfoGraphDB**: Provides a fast and flexible static database for master data. Using the
59//!   **Repository** this can be used to load master data from e.g. an S3 Bucket or a git repository
60//!   into fast lookup tables or code sets. These permit to perform all kinds of lookups,
61//!   reverse-lookups, "search as you type" searches and automatic translation management (even for
62//!   tables with thousands of rows / structured documents). More infos: [crate::idb]
63//! * **Repository**: The repository is used to fetch files from various sources and invoking
64//!   appropriate loaders so that the data can be used (e.g. as IDB table). See [crate::repository]
65//!
66//! # Examples
67//! A complete example of using Jupiter can be found here:
68//! [Jupiter IO](https://github.com/scireum/jupiter/tree/master/jupiter-io).
69//!
70//! Still a short example on how to initialize the library can be found here [Builder](builder::Builder).
71//! Some example commands can be found in the implementation of the [core](core) commands.
72//!
73//! # Using Jupiter
74//! **Jupiter** is intended to be used as a framework for your custom application. However the
75//! example instance [Jupiter IO](https://github.com/scireum/jupiter/tree/master/jupiter-io) which
76//! features an **LRU cache** and an **InfoGraphDB** instance can also be directly used via docker:
77//! [Docker image](https://hub.docker.com/repository/docker/scireum/jupiter-io).
78//!
79//! Further info can be found on [crates.io/crates/jupiter](https://crates.io/crates/jupiter).
80//! As well as on GitHub: [github.com/scireum/jupiter](https://github.com/scireum/jupiter)
81#![deny(
82    warnings,
83    missing_docs,
84    trivial_casts,
85    trivial_numeric_casts,
86    unused_extern_crates,
87    unused_import_braces,
88    unused_results
89)]
90use simplelog::{format_description, ConfigBuilder, LevelFilter, SimpleLogger};
91use std::sync::Once;
92
93pub mod average;
94pub mod builder;
95pub mod commands;
96pub mod config;
97pub mod core;
98pub mod fmt;
99pub mod idb;
100pub mod ig;
101pub mod lru;
102pub mod platform;
103pub mod repository;
104pub mod request;
105pub mod response;
106pub mod server;
107pub mod signals;
108
109/// Contains the version of the Jupiter library.
110pub const JUPITER_VERSION: &str = "4.1.1";
111
112/// Contains the git commit hash of the Jupiter build being used.
113pub const JUPITER_REVISION: &str = "4aa4a22fbb25e5cd6eb8bbfcce388df9d7c1a84a";
114
115/// Initializes the logging system.
116///
117/// Note that most probably the simplest way is to use a [Builder](builder::Builder) to set up the
118/// framework, which will also set up logging if enabled.
119pub fn init_logging() {
120    static INIT_LOGGING: Once = Once::new();
121
122    // We need to do this as otherwise the integration tests might crash as the logging system
123    // is initialized several times...
124    INIT_LOGGING.call_once(|| {
125        if let Err(error) = SimpleLogger::init(
126            LevelFilter::Debug,
127            ConfigBuilder::new()
128                .set_time_format_custom(format_description!(
129                    "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]"
130                ))
131                .set_thread_level(LevelFilter::Trace)
132                .set_target_level(LevelFilter::Error)
133                .set_location_level(LevelFilter::Trace)
134                .build(),
135        ) {
136            panic!("Failed to initialize logging system: {}", error);
137        }
138    });
139}
140
141/// Provides a simple macro to execute an async lambda within `tokio::spawn`.
142///
143/// Note that this also applies std::mem::drop on the returned closure to make
144/// clippy happy.
145///
146/// # Example
147/// ```rust
148/// # #[macro_use] extern crate jupiter;
149/// # #[tokio::main]
150/// # async fn main() {
151/// spawn!(async move {
152///     // perform some async stuff here...
153/// });
154/// # }
155#[macro_export]
156macro_rules! spawn {
157    ($e:expr) => {{
158        std::mem::drop(tokio::spawn($e));
159    }};
160}
161
162#[cfg(test)]
163mod testing {
164    use redis::{Connection, RedisError};
165    use std::sync::Mutex;
166    use tokio::time::Duration;
167
168    lazy_static::lazy_static! {
169        /// Provides a global lock which has to be acquired if a test operates on shared
170        /// resources. This would either be our test port (1503) on which we start our
171        /// local server for integrations tests or the repository which operates on the
172        /// file system. Using this lock, we can still execute all other tests in parallel
173        /// and only block if required.
174        pub static ref SHARED_TEST_RESOURCES: Mutex<()> = Mutex::new(());
175    }
176
177    /// Executes async code within a single threaded tokio runtime.
178    pub fn test_async<F: std::future::Future>(future: F) {
179        use tokio::runtime;
180
181        let rt = runtime::Builder::new_current_thread()
182            .enable_all()
183            .build()
184            .unwrap();
185
186        let _ = rt.block_on(future);
187    }
188
189    /// Executes a blocking Redis query in an async fashion.
190    ///
191    /// This is required as we must not block tokio in any way. Note that the redis create itself
192    /// would permit async queries, however, this seems to rely on a previous version of tokio
193    /// which crashes with our version (tokio 1.0.0).
194    pub async fn query_redis_async<T, Q>(query: Q) -> Option<T>
195    where
196        Q: FnOnce(&mut Connection) -> Result<T, RedisError> + Send + Sync + 'static,
197        T: Send + 'static,
198    {
199        let result = tokio::task::spawn_blocking(|| {
200            let client = redis::Client::open("redis://127.0.0.1:1503").unwrap();
201            let mut con = client
202                .get_connection_with_timeout(Duration::from_secs(5))
203                .unwrap();
204            query(&mut con)
205        })
206        .await;
207
208        match result {
209            Ok(Ok(result)) => Some(result),
210            _ => None,
211        }
212    }
213}