Skip to content

Commit b1c89cd

Browse files
committed
make max_pending_rows configurable and increase the default from 128 to 256
closes #441
1 parent fd0ea23 commit b1c89cd

File tree

4 files changed

+16
-5
lines changed

4 files changed

+16
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
- Add the ability to use local Woff2 fonts in the [shell](https://sql.ophir.dev/documentation.sql?component=shell#component) component. This is useful to use custom fonts in your website, without depending on google fonts (and disclosing your users' IP addresses to google).
3333
- Add a `fixed_top_menu` attribute to make the top menu sticky. This is useful to keep the menu visible even when the user scrolls down the page.
3434
- Add a `wrap` attribute to the `list` component to wrap items on multiple lines when they are too long.
35+
- New `max_pending_rows` [configuration option](https://sql.ophir.dev/configuration.md) to limit the number of messages that can be sent to the client before they are read. Usefule when sending large amounts of data to slow clients.
3536
3637
## 0.23.0 (2024-06-09)
3738

configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Here are the available configuration options and their default values:
2323
| `configuration_directory` | `./sqlpage/` | The directory where the `sqlpage.json` file is located. This is used to find the path to [`templates/`](https://sql.ophir.dev/custom_components.sql), [`migrations/`](https://sql.ophir.dev/your-first-sql-website/migrations.sql), and `on_connect.sql`. Obviously, this configuration parameter can be set only through environment variables, not through the `sqlpage.json` file itself in order to find the `sqlpage.json` file. Be careful not to use a path that is accessible from the public WEB_ROOT |
2424
| `allow_exec` | false | Allow usage of the `sqlpage.exec` function. Do this only if all users with write access to sqlpage query files and to the optional `sqlpage_files` table on the database are trusted. |
2525
| `max_uploaded_file_size` | 5242880 | Maximum size of uploaded files in bytes. Defaults to 5 MiB. |
26+
| `max_pending_rows` | 256 | Maximum number of rendered rows that can be queued up in memory when a client is slow to receive them. |
2627
| `https_domain` | | Domain name to request a certificate for. Setting this parameter will automatically make SQLPage listen on port 443 and request an SSL certificate. The server will take a little bit longer to start the first time it has to request a certificate. |
2728
| `https_certificate_email` | contact@<https_domain> | The email address to use when requesting a certificate. |
2829
| `https_certificate_cache_dir` | ./sqlpage/https | A writeable directory where to cache the certificates, so that SQLPage can serve https traffic immediately when it restarts. |

src/app_config.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ pub struct AppConfig {
8989
default = "default_site_prefix"
9090
)]
9191
pub site_prefix: String,
92+
93+
/// Maximum number of messages that can be stored in memory before sending them to the client.
94+
#[serde(default = "default_max_pending_rows")]
95+
pub max_pending_rows: usize,
9296
}
9397

9498
impl AppConfig {
@@ -148,7 +152,7 @@ pub fn load_from_file(config_file: &Path) -> anyhow::Result<AppConfig> {
148152
let app_config = config
149153
.try_deserialize::<AppConfig>()
150154
.with_context(|| "Unable to load configuration")?;
151-
log::debug!("Loaded configuration: {:?}", app_config);
155+
log::debug!("Loaded configuration: {:#?}", app_config);
152156
Ok(app_config)
153157
}
154158

@@ -294,6 +298,10 @@ fn default_https_acme_directory_url() -> String {
294298
"https://acme-v02.api.letsencrypt.org/directory".to_string()
295299
}
296300

301+
fn default_max_pending_rows() -> usize {
302+
256
303+
}
304+
297305
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone, Copy, Eq, Default)]
298306
#[serde(rename_all = "lowercase")]
299307
pub enum DevOrProd {

src/webserver/http.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ use tokio::sync::mpsc;
3232

3333
/// If the sending queue exceeds this number of outgoing messages, an error will be thrown
3434
/// This prevents a single request from using up all available memory
35-
const MAX_PENDING_MESSAGES: usize = 128;
3635
3736
#[derive(Clone)]
3837
pub struct ResponseWriter {
@@ -76,9 +75,10 @@ impl ResponseWriter {
7675
.await
7776
.map_err(|err| {
7877
use std::io::{Error, ErrorKind};
78+
let capacity = self.response_bytes.capacity();
7979
Error::new(
8080
ErrorKind::BrokenPipe,
81-
format!("The HTTP response writer with a capacity of {MAX_PENDING_MESSAGES} has already been closed: {err}"),
81+
format!("The HTTP response writer with a capacity of {capacity} has already been closed: {err}"),
8282
)
8383
})
8484
}
@@ -96,7 +96,7 @@ impl Write for ResponseWriter {
9696
.map_err(|e|
9797
std::io::Error::new(
9898
std::io::ErrorKind::WouldBlock,
99-
format!("{e}: Database messages limit exceeded. The server cannot store more than {} pending messages in memory.", self.response_bytes.capacity())
99+
format!("{e}: Row limit exceeded. The server cannot store more than {} pending messages in memory. Try again later or increase max_pending_rows in the configuration.", self.response_bytes.max_capacity())
100100
)
101101
)
102102
}
@@ -157,7 +157,8 @@ async fn build_response_header_and_stream<S: Stream<Item = DbItem>>(
157157
database_entries: S,
158158
layout_context: &LayoutContext,
159159
) -> anyhow::Result<ResponseWithWriter<S>> {
160-
let (sender, receiver) = mpsc::channel(MAX_PENDING_MESSAGES);
160+
let chan_size = app_state.config.max_pending_rows;
161+
let (sender, receiver) = mpsc::channel(chan_size);
161162
let writer = ResponseWriter::new(sender);
162163
let mut head_context = HeaderContext::new(app_state, layout_context, writer);
163164
let mut stream = Box::pin(database_entries);

0 commit comments

Comments
 (0)