File tree Expand file tree Collapse file tree 4 files changed +80
-8
lines changed Expand file tree Collapse file tree 4 files changed +80
-8
lines changed Original file line number Diff line number Diff line change 24
24
- Expose runtime utilization metric in autoscaler endpoint. ([ #4606 ] ( https://github.com/getsentry/relay/pull/4606 ) )
25
25
- Bump the revision of ` sysinfo ` to the revision at ` 15b3be3273ba286740122fed7bb7dccd2a79dc8f ` . ([ #4613 ] ( https://github.com/getsentry/relay/pull/4613 ) )
26
26
- Switch the processor and store to ` async ` . ([ #4552 ] ( https://github.com/getsentry/relay/pull/4552 ) )
27
+ - Validate the spooling memory configuration on startup. ([ #4617 ] ( https://github.com/getsentry/relay/pull/4617 ) )
27
28
28
29
## 25.3.0
29
30
Original file line number Diff line number Diff line change @@ -77,6 +77,12 @@ impl MemoryStat {
77
77
} ) )
78
78
}
79
79
80
+ /// Returns the current memory data without instantiating [`MemoryStat`].
81
+ pub fn current_memory ( ) -> Memory {
82
+ let mut system = System :: new ( ) ;
83
+ Self :: refresh_memory ( & mut system)
84
+ }
85
+
80
86
/// Returns a copy of the most up-to-date memory data.
81
87
pub fn memory ( & self ) -> Memory {
82
88
self . try_update ( ) ;
@@ -103,6 +109,18 @@ impl MemoryStat {
103
109
memory
104
110
}
105
111
112
+ /// Updates the memory readings unconditionally.
113
+ fn update ( & self ) {
114
+ let mut system = self
115
+ . 0
116
+ . system
117
+ . lock ( )
118
+ . unwrap_or_else ( |system| system. into_inner ( ) ) ;
119
+
120
+ let updated_memory = Self :: refresh_memory ( & mut system) ;
121
+ self . 0 . memory . store ( Arc :: new ( updated_memory) ) ;
122
+ }
123
+
106
124
/// Updates the memory readings if at least `refresh_frequency_ms` has passed.
107
125
fn try_update ( & self ) {
108
126
let last_update = self . 0 . last_update . load ( Ordering :: Relaxed ) ;
@@ -126,14 +144,7 @@ impl MemoryStat {
126
144
return ;
127
145
}
128
146
129
- let mut system = self
130
- . 0
131
- . system
132
- . lock ( )
133
- . unwrap_or_else ( |system| system. into_inner ( ) ) ;
134
-
135
- let updated_memory = Self :: refresh_memory ( & mut system) ;
136
- self . 0 . memory . store ( Arc :: new ( updated_memory) ) ;
147
+ self . update ( ) ;
137
148
}
138
149
}
139
150
Original file line number Diff line number Diff line change 2
2
use anyhow:: Context ;
3
3
use anyhow:: Result ;
4
4
use relay_config:: { Config , RelayMode } ;
5
+ use relay_server:: MemoryStat ;
6
+
7
+ /// Validates that the `batch_size_bytes` of the configuration is correct and doesn't lead to
8
+ /// deadlocks in the buffer.
9
+ fn assert_batch_size_bytes ( config : & Config ) -> Result < ( ) > {
10
+ // We create a temporary memory reading used just for the config check.
11
+ let memory = MemoryStat :: current_memory ( ) ;
12
+
13
+ // We expect the batch size for the spooler to be 10% of the memory threshold over which the
14
+ // buffer stops unspooling.
15
+ //
16
+ // The 10% threshold was arbitrarily chosen to give the system leeway when spooling.
17
+ let configured_batch_size_bytes = config. spool_envelopes_batch_size_bytes ( ) as f32 ;
18
+ let maximum_batch_size_bytes =
19
+ memory. total as f32 * config. spool_max_backpressure_memory_percent ( ) * 0.1 ;
20
+
21
+ if configured_batch_size_bytes > maximum_batch_size_bytes {
22
+ anyhow:: bail!(
23
+ "the configured `spool.envelopes.batch_size_bytes` is {} bytes but it must be <= than {} bytes" ,
24
+ configured_batch_size_bytes,
25
+ maximum_batch_size_bytes
26
+ )
27
+ }
28
+
29
+ Ok ( ( ) )
30
+ }
5
31
6
32
pub fn check_config ( config : & Config ) -> Result < ( ) > {
7
33
if config. relay_mode ( ) == RelayMode :: Managed && config. credentials ( ) . is_none ( ) {
@@ -31,6 +57,8 @@ pub fn check_config(config: &Config) -> Result<()> {
31
57
}
32
58
}
33
59
60
+ assert_batch_size_bytes ( config) ?;
61
+
34
62
Ok ( ( ) )
35
63
}
36
64
Original file line number Diff line number Diff line change @@ -85,6 +85,38 @@ def get_project_config():
85
85
conn .close ()
86
86
87
87
88
+ def test_batch_size_bytes_asserted (mini_sentry , relay ):
89
+ from time import sleep
90
+
91
+ # Create a temporary directory for the sqlite db.
92
+ db_file_path = os .path .join (tempfile .mkdtemp (), "database.db" )
93
+
94
+ get_project_config_original = mini_sentry .app .view_functions ["get_project_config" ]
95
+
96
+ @mini_sentry .app .endpoint ("get_project_config" )
97
+ def get_project_config ():
98
+ sleep (1 ) # Causes the process to wait for one second before shutting down
99
+ return get_project_config_original ()
100
+
101
+ project_id = 42
102
+ mini_sentry .add_basic_project_config (project_id )
103
+
104
+ mini_sentry .fail_on_relay_error = False
105
+
106
+ relay = relay (
107
+ mini_sentry ,
108
+ {
109
+ "limits" : {"shutdown_timeout" : 2 },
110
+ # Arbitrarily chosen high value to always fail.
111
+ "spool" : {"envelopes" : {"path" : db_file_path , "batch_size_bytes" : "10tb" }},
112
+ },
113
+ wait_health_check = False ,
114
+ )
115
+
116
+ # Assert that the process exited with an error (non-zero exit code)
117
+ assert relay .wait_for_exit () != 0 , "Expected Relay to not start, but it started"
118
+
119
+
88
120
@pytest .mark .skip ("Flaky test" )
89
121
def test_forced_shutdown (mini_sentry , relay ):
90
122
from time import sleep
You can’t perform that action at this time.
0 commit comments