Spaces:
Running
Running
Merge pull request #599 from neon-mmd/FIX/592_redis-does-not-invalidate-cached-results
Browse files- Cargo.lock +14 -4
- Cargo.toml +3 -4
- src/cache/redis_cacher.rs +12 -3
- src/server/routes/search.rs +20 -28
Cargo.lock
CHANGED
@@ -851,7 +851,7 @@ dependencies = [
|
|
851 |
"clap",
|
852 |
"criterion-plot",
|
853 |
"is-terminal",
|
854 |
-
"itertools",
|
855 |
"num-traits",
|
856 |
"once_cell",
|
857 |
"oorandom",
|
@@ -870,7 +870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
870 |
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
871 |
dependencies = [
|
872 |
"cast",
|
873 |
-
"itertools",
|
874 |
]
|
875 |
|
876 |
[[package]]
|
@@ -1881,6 +1881,15 @@ dependencies = [
|
|
1881 |
"either",
|
1882 |
]
|
1883 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1884 |
[[package]]
|
1885 |
name = "itoa"
|
1886 |
version = "0.4.8"
|
@@ -1983,7 +1992,7 @@ dependencies = [
|
|
1983 |
"cssparser-color",
|
1984 |
"data-encoding",
|
1985 |
"getrandom",
|
1986 |
-
"itertools",
|
1987 |
"lazy_static",
|
1988 |
"parcel_selectors",
|
1989 |
"paste",
|
@@ -4440,7 +4449,7 @@ dependencies = [
|
|
4440 |
|
4441 |
[[package]]
|
4442 |
name = "websurfx"
|
4443 |
-
version = "1.17.
|
4444 |
dependencies = [
|
4445 |
"actix-cors",
|
4446 |
"actix-files",
|
@@ -4460,6 +4469,7 @@ dependencies = [
|
|
4460 |
"error-stack",
|
4461 |
"fake-useragent",
|
4462 |
"futures 0.3.30",
|
|
|
4463 |
"keyword_extraction",
|
4464 |
"lightningcss",
|
4465 |
"log",
|
|
|
851 |
"clap",
|
852 |
"criterion-plot",
|
853 |
"is-terminal",
|
854 |
+
"itertools 0.10.5",
|
855 |
"num-traits",
|
856 |
"once_cell",
|
857 |
"oorandom",
|
|
|
870 |
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
871 |
dependencies = [
|
872 |
"cast",
|
873 |
+
"itertools 0.10.5",
|
874 |
]
|
875 |
|
876 |
[[package]]
|
|
|
1881 |
"either",
|
1882 |
]
|
1883 |
|
1884 |
+
[[package]]
|
1885 |
+
name = "itertools"
|
1886 |
+
version = "0.13.0"
|
1887 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1888 |
+
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
1889 |
+
dependencies = [
|
1890 |
+
"either",
|
1891 |
+
]
|
1892 |
+
|
1893 |
[[package]]
|
1894 |
name = "itoa"
|
1895 |
version = "0.4.8"
|
|
|
1992 |
"cssparser-color",
|
1993 |
"data-encoding",
|
1994 |
"getrandom",
|
1995 |
+
"itertools 0.10.5",
|
1996 |
"lazy_static",
|
1997 |
"parcel_selectors",
|
1998 |
"paste",
|
|
|
4449 |
|
4450 |
[[package]]
|
4451 |
name = "websurfx"
|
4452 |
+
version = "1.17.20"
|
4453 |
dependencies = [
|
4454 |
"actix-cors",
|
4455 |
"actix-files",
|
|
|
4469 |
"error-stack",
|
4470 |
"fake-useragent",
|
4471 |
"futures 0.3.30",
|
4472 |
+
"itertools 0.13.0",
|
4473 |
"keyword_extraction",
|
4474 |
"lightningcss",
|
4475 |
"log",
|
Cargo.toml
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
[package]
|
2 |
name = "websurfx"
|
3 |
-
version = "1.17.
|
4 |
edition = "2021"
|
5 |
description = "An open-source alternative to Searx that provides clean, ad-free, and organic results with incredible speed while keeping privacy and security in mind."
|
6 |
repository = "https://github.com/neon-mmd/websurfx"
|
@@ -82,14 +82,13 @@ base64 = { version = "0.21.5", default-features = false, features = [
|
|
82 |
cfg-if = { version = "1.0.0", default-features = false, optional = true }
|
83 |
keyword_extraction = { version = "1.4.3", default-features = false, features = [
|
84 |
"tf_idf",
|
85 |
-
|
86 |
-
|
87 |
] }
|
88 |
|
89 |
stop-words = { version = "0.8.0", default-features = false, features = ["iso"] }
|
90 |
thesaurus = { version = "0.5.2", default-features = false, optional = true, features = [
|
91 |
"moby",
|
92 |
-
]
|
|
|
93 |
|
94 |
[dev-dependencies]
|
95 |
rusty-hook = { version = "^0.11.2", default-features = false }
|
|
|
1 |
[package]
|
2 |
name = "websurfx"
|
3 |
+
version = "1.17.20"
|
4 |
edition = "2021"
|
5 |
description = "An open-source alternative to Searx that provides clean, ad-free, and organic results with incredible speed while keeping privacy and security in mind."
|
6 |
repository = "https://github.com/neon-mmd/websurfx"
|
|
|
82 |
cfg-if = { version = "1.0.0", default-features = false, optional = true }
|
83 |
keyword_extraction = { version = "1.4.3", default-features = false, features = [
|
84 |
"tf_idf",
|
|
|
|
|
85 |
] }
|
86 |
|
87 |
stop-words = { version = "0.8.0", default-features = false, features = ["iso"] }
|
88 |
thesaurus = { version = "0.5.2", default-features = false, optional = true, features = [
|
89 |
"moby",
|
90 |
+
]}
|
91 |
+
itertools = {version = "0.13.0", default-features = false}
|
92 |
|
93 |
[dev-dependencies]
|
94 |
rusty-hook = { version = "^0.11.2", default-features = false }
|
src/cache/redis_cacher.rs
CHANGED
@@ -4,7 +4,10 @@
|
|
4 |
use super::error::CacheError;
|
5 |
use error_stack::Report;
|
6 |
use futures::stream::FuturesUnordered;
|
7 |
-
use redis::{
|
|
|
|
|
|
|
8 |
|
9 |
/// A constant holding the redis pipeline size.
|
10 |
const REDIS_PIPELINE_SIZE: usize = 3;
|
@@ -139,8 +142,14 @@ impl RedisCache {
|
|
139 |
self.current_connection = Default::default();
|
140 |
|
141 |
for (key, json_result) in keys.zip(json_results) {
|
142 |
-
self.pipeline
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
}
|
145 |
|
146 |
let mut result: Result<(), RedisError> = self
|
|
|
4 |
use super::error::CacheError;
|
5 |
use error_stack::Report;
|
6 |
use futures::stream::FuturesUnordered;
|
7 |
+
use redis::{
|
8 |
+
aio::ConnectionManager, AsyncCommands, Client, ExistenceCheck, RedisError, SetExpiry,
|
9 |
+
SetOptions,
|
10 |
+
};
|
11 |
|
12 |
/// A constant holding the redis pipeline size.
|
13 |
const REDIS_PIPELINE_SIZE: usize = 3;
|
|
|
142 |
self.current_connection = Default::default();
|
143 |
|
144 |
for (key, json_result) in keys.zip(json_results) {
|
145 |
+
self.pipeline.set_options(
|
146 |
+
key,
|
147 |
+
json_result,
|
148 |
+
SetOptions::default()
|
149 |
+
.conditional_set(ExistenceCheck::NX)
|
150 |
+
.get(true)
|
151 |
+
.with_expiration(SetExpiry::EX(self.cache_ttl.into())),
|
152 |
+
);
|
153 |
}
|
154 |
|
155 |
let mut result: Result<(), RedisError> = self
|
src/server/routes/search.rs
CHANGED
@@ -12,6 +12,7 @@ use crate::{
|
|
12 |
results::aggregator::aggregate,
|
13 |
};
|
14 |
use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
|
|
|
15 |
use regex::Regex;
|
16 |
use std::borrow::Cow;
|
17 |
use tokio::{
|
@@ -40,7 +41,6 @@ pub async fn search(
|
|
40 |
config: web::Data<&'static Config>,
|
41 |
cache: web::Data<&'static SharedCache>,
|
42 |
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
43 |
-
use std::sync::Arc;
|
44 |
let params = web::Query::<SearchParams>::from_query(req.query_string())?;
|
45 |
match ¶ms.q {
|
46 |
Some(query) => {
|
@@ -83,44 +83,36 @@ pub async fn search(
|
|
83 |
let previous_page = page.saturating_sub(1);
|
84 |
let next_page = page + 1;
|
85 |
|
86 |
-
let
|
87 |
if page != previous_page {
|
88 |
let (previous_results, current_results, next_results) = join!(
|
89 |
get_results(previous_page),
|
90 |
get_results(page),
|
91 |
get_results(next_page)
|
92 |
);
|
93 |
-
let (parsed_previous_results, parsed_next_results) =
|
94 |
-
(previous_results?, next_results?);
|
95 |
|
96 |
-
|
97 |
-
[
|
98 |
-
parsed_previous_results.1,
|
99 |
-
results.1.clone(),
|
100 |
-
parsed_next_results.1,
|
101 |
-
],
|
102 |
-
[
|
103 |
-
parsed_previous_results.0,
|
104 |
-
results.0.clone(),
|
105 |
-
parsed_next_results.0,
|
106 |
-
],
|
107 |
-
);
|
108 |
|
109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
|
111 |
tokio::spawn(async move { cache.cache_results(&results_list, &cache_keys).await });
|
112 |
} else {
|
113 |
let (current_results, next_results) =
|
114 |
join!(get_results(page), get_results(page + 1));
|
115 |
|
116 |
-
|
117 |
-
|
118 |
-
results = Arc::new(current_results?);
|
119 |
|
120 |
-
let (
|
121 |
-
[results.
|
122 |
-
|
123 |
-
|
|
|
124 |
|
125 |
tokio::spawn(async move { cache.cache_results(&results_list, &cache_keys).await });
|
126 |
}
|
@@ -163,7 +155,7 @@ async fn results(
|
|
163 |
query: &str,
|
164 |
page: u32,
|
165 |
search_settings: &server_models::Cookie<'_>,
|
166 |
-
) -> Result<(SearchResults, String), Box<dyn std::error::Error>> {
|
167 |
// eagerly parse cookie value to evaluate safe search level
|
168 |
let safe_search_level = search_settings.safe_search_level;
|
169 |
|
@@ -182,7 +174,7 @@ async fn results(
|
|
182 |
// check if fetched cache results was indeed fetched or it was an error and if so
|
183 |
// handle the data accordingly.
|
184 |
match cached_results {
|
185 |
-
Ok(results) => Ok((results, cache_key)),
|
186 |
Err(_) => {
|
187 |
if safe_search_level == 4 {
|
188 |
let mut results: SearchResults = SearchResults::default();
|
@@ -196,7 +188,7 @@ async fn results(
|
|
196 |
.cache_results(&[results.clone()], &[cache_key.clone()])
|
197 |
.await?;
|
198 |
results.set_safe_search_level(safe_search_level);
|
199 |
-
return Ok((results, cache_key));
|
200 |
}
|
201 |
}
|
202 |
|
@@ -235,7 +227,7 @@ async fn results(
|
|
235 |
.cache_results(&[results.clone()], &[cache_key.clone()])
|
236 |
.await?;
|
237 |
results.set_safe_search_level(safe_search_level);
|
238 |
-
Ok((results, cache_key))
|
239 |
}
|
240 |
}
|
241 |
}
|
|
|
12 |
results::aggregator::aggregate,
|
13 |
};
|
14 |
use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
|
15 |
+
use itertools::Itertools;
|
16 |
use regex::Regex;
|
17 |
use std::borrow::Cow;
|
18 |
use tokio::{
|
|
|
41 |
config: web::Data<&'static Config>,
|
42 |
cache: web::Data<&'static SharedCache>,
|
43 |
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
|
|
44 |
let params = web::Query::<SearchParams>::from_query(req.query_string())?;
|
45 |
match ¶ms.q {
|
46 |
Some(query) => {
|
|
|
83 |
let previous_page = page.saturating_sub(1);
|
84 |
let next_page = page + 1;
|
85 |
|
86 |
+
let results: (SearchResults, String, bool);
|
87 |
if page != previous_page {
|
88 |
let (previous_results, current_results, next_results) = join!(
|
89 |
get_results(previous_page),
|
90 |
get_results(page),
|
91 |
get_results(next_page)
|
92 |
);
|
|
|
|
|
93 |
|
94 |
+
results = current_results?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
+
let (results_list, cache_keys): (Vec<SearchResults>, Vec<String>) =
|
97 |
+
[previous_results?, results.clone(), next_results?]
|
98 |
+
.into_iter()
|
99 |
+
.filter_map(|(result, cache_key, flag)| {
|
100 |
+
dbg!(flag).then_some((result, cache_key))
|
101 |
+
})
|
102 |
+
.multiunzip();
|
103 |
|
104 |
tokio::spawn(async move { cache.cache_results(&results_list, &cache_keys).await });
|
105 |
} else {
|
106 |
let (current_results, next_results) =
|
107 |
join!(get_results(page), get_results(page + 1));
|
108 |
|
109 |
+
results = current_results?;
|
|
|
|
|
110 |
|
111 |
+
let (results_list, cache_keys): (Vec<SearchResults>, Vec<String>) =
|
112 |
+
[results.clone(), next_results?]
|
113 |
+
.into_iter()
|
114 |
+
.filter_map(|(result, cache_key, flag)| flag.then_some((result, cache_key)))
|
115 |
+
.multiunzip();
|
116 |
|
117 |
tokio::spawn(async move { cache.cache_results(&results_list, &cache_keys).await });
|
118 |
}
|
|
|
155 |
query: &str,
|
156 |
page: u32,
|
157 |
search_settings: &server_models::Cookie<'_>,
|
158 |
+
) -> Result<(SearchResults, String, bool), Box<dyn std::error::Error>> {
|
159 |
// eagerly parse cookie value to evaluate safe search level
|
160 |
let safe_search_level = search_settings.safe_search_level;
|
161 |
|
|
|
174 |
// check if fetched cache results was indeed fetched or it was an error and if so
|
175 |
// handle the data accordingly.
|
176 |
match cached_results {
|
177 |
+
Ok(results) => Ok((results, cache_key, false)),
|
178 |
Err(_) => {
|
179 |
if safe_search_level == 4 {
|
180 |
let mut results: SearchResults = SearchResults::default();
|
|
|
188 |
.cache_results(&[results.clone()], &[cache_key.clone()])
|
189 |
.await?;
|
190 |
results.set_safe_search_level(safe_search_level);
|
191 |
+
return Ok((results, cache_key, true));
|
192 |
}
|
193 |
}
|
194 |
|
|
|
227 |
.cache_results(&[results.clone()], &[cache_key.clone()])
|
228 |
.await?;
|
229 |
results.set_safe_search_level(safe_search_level);
|
230 |
+
Ok((results, cache_key, true))
|
231 |
}
|
232 |
}
|
233 |
}
|