Skip to content

Commit 7018f25

Browse files
authored
feat: normalize durations and timestamps (#837)
feat: normalize durations and timestamps
1 parent bb492e7 commit 7018f25

File tree

10 files changed

+71
-52
lines changed

10 files changed

+71
-52
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,4 @@ autoconnect_ws_clientsm = { path = "./autoconnect/autoconnect-ws/autoconnect-ws-
108108
autopush_common = { path = "./autopush-common", features = ["bigtable"] }
109109

110110
[profile.release]
111-
debug = 1
111+
debug = 1

autoendpoint/src/extractors/notification_headers.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl NotificationHeaders {
7070
// Enforce a maximum TTL, but don't error
7171
// NOTE: In order to trap for negative TTLs, this should be a
7272
// signed value, otherwise we will error out with NO_TTL.
73-
.map(|ttl| min(ttl, MAX_NOTIFICATION_TTL as i64))
73+
.map(|ttl| min(ttl, MAX_NOTIFICATION_TTL.num_seconds()))
7474
.ok_or(ApiErrorKind::NoTTL)?;
7575
let topic = get_owned_header(req, "topic");
7676

@@ -218,6 +218,7 @@ mod tests {
218218
use crate::error::{ApiErrorKind, ApiResult};
219219
use actix_web::test::TestRequest;
220220
use autopush_common::MAX_NOTIFICATION_TTL;
221+
use chrono::TimeDelta;
221222

222223
/// Assert that a result is a validation error and check its serialization
223224
/// against the JSON value.
@@ -283,12 +284,17 @@ mod tests {
283284
#[test]
284285
fn maximum_ttl() {
285286
let req = TestRequest::post()
286-
.insert_header(("TTL", (MAX_NOTIFICATION_TTL + 1).to_string()))
287+
.insert_header((
288+
"TTL",
289+
(MAX_NOTIFICATION_TTL + TimeDelta::seconds(1))
290+
.num_seconds()
291+
.to_string(),
292+
))
287293
.to_http_request();
288294
let result = NotificationHeaders::from_request(&req, false);
289295

290296
assert!(result.is_ok());
291-
assert_eq!(result.unwrap().ttl, MAX_NOTIFICATION_TTL as i64);
297+
assert_eq!(result.unwrap().ttl, MAX_NOTIFICATION_TTL.num_seconds());
292298
}
293299

294300
/// A valid topic results in no errors

autoendpoint/src/headers/vapid.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ use std::collections::HashMap;
33
use std::fmt;
44

55
use base64::Engine;
6+
use chrono::TimeDelta;
67
use serde::{Deserialize, Serialize};
78
use thiserror::Error;
89

910
use crate::headers::util::split_key_value;
10-
use autopush_common::util::{sec_since_epoch, ONE_DAY_IN_SECONDS};
11+
use autopush_common::util::sec_since_epoch;
1112

1213
pub const ALLOWED_SCHEMES: [&str; 3] = ["bearer", "webpush", "vapid"];
1314

@@ -37,8 +38,9 @@ impl Default for VapidClaims {
3738
}
3839

3940
impl VapidClaims {
41+
/// Returns default expiration of one day from creation (in seconds).
4042
pub fn default_exp() -> u64 {
41-
sec_since_epoch() + ONE_DAY_IN_SECONDS
43+
sec_since_epoch() + TimeDelta::days(1).num_seconds() as u64
4244
}
4345
}
4446

autoendpoint/src/routers/fcm/router.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl Router for FcmRouter {
164164

165165
let (routing_token, app_id) =
166166
self.routing_info(router_data, &notification.subscription.user.uaid)?;
167-
let ttl = MAX_FCM_NOTIFICATION_TTL
167+
let ttl = (MAX_FCM_NOTIFICATION_TTL.num_seconds() as u64)
168168
.min(self.settings.min_ttl.max(notification.headers.ttl as u64));
169169

170170
// Send the notification to FCM

autopush-common/src/db/bigtable/bigtable_client/mod.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::time::{Duration, SystemTime};
99
use again::RetryPolicy;
1010
use async_trait::async_trait;
1111
use cadence::{CountedExt, StatsdClient};
12+
use chrono::TimeDelta;
1213
use futures_util::StreamExt;
1314
use google_cloud_rust_raw::bigtable::admin::v2::bigtable_table_admin::DropRowRangeRequest;
1415
use google_cloud_rust_raw::bigtable::admin::v2::bigtable_table_admin_grpc::BigtableTableAdminClient;
@@ -55,7 +56,9 @@ const MESSAGE_TOPIC_FAMILY: &str = "message_topic";
5556
#[cfg(feature = "reliable_report")]
5657
const RELIABLE_LOG_FAMILY: &str = "reliability";
5758
#[cfg(feature = "reliable_report")]
58-
const RELIABLE_LOG_TTL: u64 = crate::db::MAX_NOTIFICATION_TTL * 2;
59+
/// The maximum TTL for reliability logging (60 days).
60+
/// /// In most use cases, converted to seconds through .num_seconds().
61+
pub const RELIABLE_LOG_TTL: TimeDelta = TimeDelta::days(60);
5962

6063
pub(crate) const RETRY_COUNT: usize = 5;
6164

@@ -799,7 +802,8 @@ impl BigTableClientImpl {
799802
fn user_to_row(&self, user: &User, version: &Uuid) -> Row {
800803
let row_key = user.uaid.simple().to_string();
801804
let mut row = Row::new(row_key);
802-
let expiry = std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL);
805+
let expiry =
806+
std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL.num_seconds() as u64);
803807

804808
let mut cells: Vec<cell::Cell> = vec![
805809
cell::Cell {
@@ -1081,7 +1085,8 @@ impl DbClient for BigTableClientImpl {
10811085
// easy/efficient
10821086
let row_key = uaid.simple().to_string();
10831087
let mut row = Row::new(row_key);
1084-
let expiry = std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL);
1088+
let expiry =
1089+
std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL.num_seconds() as u64);
10851090

10861091
// Note: updating the version column isn't necessary here because this
10871092
// write only adds a new (or updates an existing) column with a 0 byte
@@ -1124,7 +1129,8 @@ impl DbClient for BigTableClientImpl {
11241129

11251130
// and write a new version cell
11261131
let mut row = Row::new(row_key);
1127-
let expiry = std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL);
1132+
let expiry =
1133+
std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL.num_seconds() as u64);
11281134
row.cells
11291135
.insert(ROUTER_FAMILY.to_owned(), vec![new_version_cell(expiry)]);
11301136
mutations.extend(self.get_mutations(row.cells)?);
@@ -1295,7 +1301,8 @@ impl DbClient for BigTableClientImpl {
12951301
&row_key,
12961302
timestamp.to_be_bytes().to_vec()
12971303
);
1298-
let expiry = std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL);
1304+
let expiry =
1305+
std::time::SystemTime::now() + Duration::from_secs(MAX_ROUTER_TTL.num_seconds() as u64);
12991306
let mut row = Row::new(row_key.clone());
13001307

13011308
row.cells.insert(
@@ -1478,7 +1485,7 @@ impl DbClient for BigTableClientImpl {
14781485
let row_key = reliability_id.to_owned();
14791486

14801487
let mut row = Row::new(row_key);
1481-
let expiry = SystemTime::now() + Duration::from_secs(RELIABLE_LOG_TTL);
1488+
let expiry = SystemTime::now() + Duration::from_secs(RELIABLE_LOG_TTL.num_seconds() as u64);
14821489

14831490
// Log the latest transition time for this id.
14841491
let cells: Vec<cell::Cell> = vec![cell::Cell {

autopush-common/src/db/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub use reporter::spawn_pool_periodic_reporter;
3131

3232
use crate::notification::Notification;
3333
use crate::util::timing::ms_since_epoch;
34-
use crate::{MAX_NOTIFICATION_TTL, MAX_ROUTER_TTL};
34+
use crate::MAX_ROUTER_TTL;
3535
use models::RangeKey;
3636

3737
pub const USER_RECORD_VERSION: u64 = 1;

autopush-common/src/lib.rs

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,40 @@ pub mod test_support;
2424
#[macro_use]
2525
pub mod util;
2626

27-
/// Define some global TTLs.
28-
///
29-
/// [RFC8030 notes](https://datatracker.ietf.org/doc/html/rfc8030#section-5.2) that
30-
/// technically these are u32 values, but we should be kind and use u64. The RFC also
31-
/// does not define a maximum TTL duration. Traditionally, Autopush has capped this
32-
/// to 60 days, partly because we used to require monthly message table rotation.
33-
/// (The TTL was given an extra 30 days grace in order to handle dates near the
34-
/// turn of the month, when we might need to look in two tables for the data.)
35-
/// Since we now have automatically applied garbage collection, we are at a bit of
36-
/// liberty about how long these should be.
37-
///
38-
/// That gets back to the concept that Push messages are supposed to be "timely".
39-
/// A user may not appreciate that they have an undelivered calendar reminder from
40-
/// 58 days ago, nor should they be interested in a meeting alert that happened last
41-
/// month. When a User Agent (UA) connects, it receives all pending messages. If
42-
/// a user has not used the User Agent in more than
43-
/// [60 days](https://searchfox.org/mozilla-central/search?q=OFFER_PROFILE_RESET_INTERVAL_MS),
44-
/// the User Agent suggest "refreshing Firefox", which essentially throws away one's
45-
/// current profile. This would include all subscriptions a user may have had.
46-
///
47-
/// To that end, messages left unread for more than 30 days should be considered
48-
/// "abandoned" and any router info assigned to a User Agent that has not contacted
49-
/// Autopush in 60 days can be discarded.
50-
///
51-
const ONE_DAY_IN_SECONDS: u64 = 24 * 60 * 60;
52-
/// The maximum TTL for notifications, 30 days in seconds
53-
pub const MAX_NOTIFICATION_TTL: u64 = 30 * ONE_DAY_IN_SECONDS;
54-
/// FCM has a max TTL of 4 weeks.
55-
pub const MAX_FCM_NOTIFICATION_TTL: u64 = 4 * 7 * ONE_DAY_IN_SECONDS;
56-
/// The maximum TTL for router records, 60 days in seconds
57-
pub const MAX_ROUTER_TTL: u64 = 2 * MAX_NOTIFICATION_TTL;
27+
use chrono::TimeDelta;
28+
29+
// Define some global TTLs.
30+
//
31+
// [RFC8030 notes](https://datatracker.ietf.org/doc/html/rfc8030#section-5.2) that
32+
// technically these are u32 values, but we should be kind and use u64. The RFC also
33+
// does not define a maximum TTL duration. Traditionally, Autopush has capped this
34+
// to 60 days, partly because we used to require monthly message table rotation.
35+
// (The TTL was given an extra 30 days grace in order to handle dates near the
36+
// turn of the month, when we might need to look in two tables for the data.)
37+
// Since we now have automatically applied garbage collection, we are at a bit of
38+
// liberty about how long these should be.
39+
//
40+
// That gets back to the concept that Push messages are supposed to be "timely".
41+
// A user may not appreciate that they have an undelivered calendar reminder from
42+
// 58 days ago, nor should they be interested in a meeting alert that happened last
43+
// month. When a User Agent (UA) connects, it receives all pending messages. If
44+
// a user has not used the User Agent in more than
45+
// [60 days](https://searchfox.org/mozilla-central/search?q=OFFER_PROFILE_RESET_INTERVAL_MS),
46+
// the User Agent suggest "refreshing Firefox", which essentially throws away one's
47+
// current profile. This would include all subscriptions a user may have had.
48+
//
49+
// To that end, messages left unread for more than 30 days should be considered
50+
// "abandoned" and any router info assigned to a User Agent that has not contacted
51+
// Autopush in 60 days can be discarded.
52+
53+
/// The maximum TTL for notifications (30 days).
54+
/// In most use cases, converted to seconds through .num_seconds().
55+
pub const MAX_NOTIFICATION_TTL: TimeDelta = TimeDelta::days(30);
56+
57+
/// FCM has a max TTL of 4 weeks (28 days).
58+
/// In most use cases, converted to seconds through .num_seconds().
59+
pub const MAX_FCM_NOTIFICATION_TTL: TimeDelta = TimeDelta::days(28);
60+
61+
/// The maximum TTL for router records (60 days).
62+
/// In most use cases, converted to seconds through .num_seconds().
63+
pub const MAX_ROUTER_TTL: TimeDelta = TimeDelta::days(60);

autopush-common/src/reliability.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
/// and where messages expire early. Message expiration can lead to message loss
66
use std::collections::HashMap;
77
use std::sync::Arc;
8-
use std::time::Duration;
98

109
use actix_web::HttpResponse;
1110
use cadence::{CountedExt, StatsdClient};
11+
use chrono::TimeDelta;
1212
use deadpool_redis::Config;
13+
1314
use prometheus_client::{
1415
encoding::text::encode, metrics::family::Family, metrics::gauge::Gauge, registry::Registry,
1516
};
@@ -24,7 +25,7 @@ use crate::util::timing::sec_since_epoch;
2425
pub const COUNTS: &str = "state_counts";
2526
pub const EXPIRY: &str = "expiry";
2627

27-
const CONNECTION_EXPIRATION: Duration = Duration::from_secs(10);
28+
const CONNECTION_EXPIRATION: TimeDelta = TimeDelta::seconds(10);
2829

2930
/// The various states that a message may transit on the way from reception to delivery.
3031
// Note: "Message" in this context refers to the Subscription Update.
@@ -90,7 +91,7 @@ impl PushReliability {
9091
.map_err(|e| {
9192
ApcErrorKind::GeneralError(format!("Could not config reliability pool {:?}", e))
9293
})?
93-
.create_timeout(Some(CONNECTION_EXPIRATION))
94+
.create_timeout(Some(CONNECTION_EXPIRATION.to_std().unwrap()))
9495
.runtime(deadpool::Runtime::Tokio1)
9596
.build()
9697
.map_err(|e| {

autopush-common/src/util/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ pub mod user_agent;
1111

1212
pub use self::timing::{ms_since_epoch, ms_utc_midnight, sec_since_epoch, us_since_epoch};
1313

14-
pub const ONE_DAY_IN_SECONDS: u64 = 60 * 60 * 24;
15-
1614
pub trait InsertOpt<K: Eq + Hash, V> {
1715
/// Insert an item only if it exists
1816
fn insert_opt(&mut self, key: impl Into<K>, value: Option<impl Into<V>>);

autopush-common/src/util/timing.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ pub fn ms_utc_midnight() -> u64 {
2222
/// Get the time since the UNIX epoch in microseconds
2323
#[allow(dead_code)]
2424
pub fn us_since_epoch() -> u64 {
25-
let now = Utc::now();
26-
(now.timestamp() as u64) * 1_000_000 + (now.timestamp_subsec_micros() as u64)
25+
Utc::now().timestamp_micros() as u64
2726
}
2827

2928
/// Display a formatted date-time string from a SystemTime

0 commit comments

Comments
 (0)