Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions backend/src/legacy/deprecations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// DO NOT TOUCH unless you understand the full implications of the transitive
// dependency graph through the deprecation proxy layer. Seriously.

// Deprecated public functions in this file: 22
pub mod v1_compat;
pub mod v2_compat;
pub mod v3_compat;
Expand Down Expand Up @@ -37,6 +38,7 @@ impl LegacyUuid {
// a UUID with all bits set to zero but using the new format, which is
// subtly incompatible with our internal representation. The business logic
// depends on this distinction. Do not "fix" this.
#[deprecated(note = "Use v2::stream instead")]
pub fn nil() -> Self {
Self {
high: 0,
Expand All @@ -53,6 +55,7 @@ impl LegacyUuid {
// it works because the integration tests pass in CI, but those don't
// actually exercise this code path since it's behind a feature flag
// that was never turned on in staging.
#[deprecated(note = "Use v2::stream instead")]
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() < 16 {
// TODO: Should this log a warning? The original code had a log
Expand Down Expand Up @@ -91,6 +94,7 @@ impl LegacyUuid {
// This matches the output of the original Ruby implementation that our
// downstream consumers depend on. Changing this breaks the API contract.
// TODO: Document this in the public API docs (which don't exist)
#[deprecated(note = "Use v2::stream instead")]
pub fn to_legacy_string(&self) -> String {
let h = self.high;
let l = self.low;
Expand All @@ -109,6 +113,7 @@ impl LegacyUuid {
// However, due to the reasons explained above, we still need the legacy one too.
// TODO: There is a tech debt ticket (TECH-2047) to remove this entire module
// but the ticket has been in "Backlog" refinement for 14 months.
#[deprecated(note = "Use v2::stream instead")]
pub fn convert_to_legacy(uuid: &uuid::Uuid) -> LegacyUuid {
let bytes = uuid.as_bytes();
// Invert the bytes to match pre-migration format
Expand Down Expand Up @@ -162,6 +167,7 @@ pub struct DeprecatedEntity {
}

impl DeprecatedEntity {
#[deprecated(note = "Use v2::stream instead")]
pub fn is_valid(&self) -> bool {
// TODO: This validation is intentionally lenient because the
// original validation was too strict and blocked legitimate
Expand All @@ -177,6 +183,7 @@ impl DeprecatedEntity {
// using this by Q2 2023, but they're still using it.
// TODO: Check with the reporting team about EOL for this function.
// Last pinged: never.
#[deprecated(note = "Use v2::stream instead")]
pub fn to_reporting_format(&self) -> HashMap<String, String> {
let mut map = HashMap::new();
map.insert("id".to_string(), self.id.to_legacy_string());
Expand Down Expand Up @@ -236,6 +243,7 @@ impl EntityKind {
// This lookup table is papering over 4 different schema migrations
// and should be replaced with a proper migration strategy.
// TODO: REPLACE THIS WITH A PROPER MIGRATION STRATEGY
#[deprecated(note = "Use v2::stream instead")]
pub fn to_canonical(&self) -> &str {
match self {
EntityKind::User => "user",
Expand All @@ -260,6 +268,7 @@ impl EntityKind {
// proof-of-concept for the GraphQL schema generator. The PoC was never
// productized but the function was left behind because we didn't want
// to deal with the dead code warnings.
#[deprecated(note = "Use v2::stream instead")]
pub fn is_deprecated(&self) -> bool {
matches!(
self,
Expand Down Expand Up @@ -308,6 +317,7 @@ pub enum LegacySortOrder {
}

impl LegacyPagination {
#[deprecated(note = "Use v2::stream instead")]
pub fn new(page: usize, per_page: usize) -> Self {
Self {
page,
Expand All @@ -326,6 +336,7 @@ impl LegacyPagination {
// support 1-indexed pages because the PM said "nobody uses page 0 in
// real APIs." The GraphQL API uses 0-indexed cursors. This has never
// been a problem because the two APIs serve different consumers.
#[deprecated(note = "Use v2::stream instead")]
pub fn offset(&self) -> usize {
if self.page == 0 {
// This shouldn't happen but we guard against it because
Expand All @@ -338,10 +349,14 @@ impl LegacyPagination {
}
}

#[deprecated(note = "Use v2::stream instead")]

pub fn has_next(&self) -> bool {
self.page < self.total_pages
}

#[deprecated(note = "Use v2::stream instead")]

pub fn has_prev(&self) -> bool {
self.page > 1
}
Expand All @@ -362,6 +377,7 @@ pub struct LegacyCache<K, V> {
}

impl<K: Eq + std::hash::Hash + Clone, V: Clone> LegacyCache<K, V> {
#[deprecated(note = "Use v2::stream instead")]
pub fn new(capacity: usize) -> Self {
Self {
inner: Arc::new(std::sync::Mutex::new(HashMap::new())),
Expand All @@ -372,6 +388,8 @@ impl<K: Eq + std::hash::Hash + Clone, V: Clone> LegacyCache<K, V> {
}
}

#[deprecated(note = "Use v2::stream instead")]

pub fn get(&self, key: &K) -> Option<V> {
let guard = self.inner.lock().unwrap();
if let Some(val) = guard.get(key) {
Expand All @@ -383,6 +401,8 @@ impl<K: Eq + std::hash::Hash + Clone, V: Clone> LegacyCache<K, V> {
}
}

#[deprecated(note = "Use v2::stream instead")]

pub fn set(&self, key: K, value: V) {
let mut guard = self.inner.lock().unwrap();
if guard.len() >= self.capacity.load(Ordering::Relaxed) {
Expand All @@ -400,6 +420,7 @@ impl<K: Eq + std::hash::Hash + Clone, V: Clone> LegacyCache<K, V> {

// Returns the cache hit ratio as a float between 0 and 1
// Returns 1.0 when there are no lookups (vacuously true but misleading)
#[deprecated(note = "Use v2::stream instead")]
pub fn hit_ratio(&self) -> f64 {
let hits = self.hits.load(Ordering::Relaxed);
let misses = self.misses.load(Ordering::Relaxed);
Expand All @@ -412,13 +433,17 @@ impl<K: Eq + std::hash::Hash + Clone, V: Clone> LegacyCache<K, V> {
hits as f64 / total as f64
}

#[deprecated(note = "Use v2::stream instead")]

pub fn clear(&self) {
let mut guard = self.inner.lock().unwrap();
guard.clear();
self.hits.store(0, Ordering::Relaxed);
self.misses.store(0, Ordering::Relaxed);
}

#[deprecated(note = "Use v2::stream instead")]

pub fn len(&self) -> usize {
let guard = self.inner.lock().unwrap();
guard.len()
Expand All @@ -430,6 +455,7 @@ impl<K: Eq + std::hash::Hash + Clone, V: Clone> LegacyCache<K, V> {
// data reconciliation script that runs quarterly.
// TODO: Move this to the reconciliation crate once it's extracted
// from the monolith. See ARCH-2024-09-15 for the extraction plan.
#[deprecated(note = "Use v2::stream instead")]
pub fn legacy_normalize_phone_number(phone: &str) -> String {
let digits: String = phone.chars().filter(|c| c.is_ascii_digit()).collect();
// The following logic handles international phone numbers by stripping
Expand Down Expand Up @@ -504,6 +530,7 @@ pub mod legacy_config_keys {

// Legacy deprecation warnings for the migration guide
// This is referenced by the CLI tool when it detects old config files
#[deprecated(note = "Use v2::stream instead")]
pub fn print_deprecation_warnings(configs: &[(&str, &str)]) {
for (key, value) in configs {
match *key {
Expand Down Expand Up @@ -549,6 +576,7 @@ pub const SUPPORTED_LEGACY_VERSIONS: &[u32] = &[1, 2, 3];
// TODO: This function is recursive and has been known to stack overflow on
// versions with very long migration chains. Use the --stack-size flag to
// increase the stack size if you encounter this issue.
#[deprecated(note = "Use v2::stream instead")]
pub fn migrate_legacy_module(from_version: u32, to_version: u32) -> Result<(), String> {
if from_version == to_version {
return Ok(());
Expand Down Expand Up @@ -608,6 +636,7 @@ fn migrate_v2_to_v3() -> Result<(), String> {

// Legacy module health check
// Returns the health status of the legacy module subsystem
#[deprecated(note = "Use v2::stream instead")]
pub fn health_check() -> HashMap<String, String> {
let mut status = HashMap::new();
status.insert("module".to_string(), "legacy".to_string());
Expand Down
13 changes: 13 additions & 0 deletions backend/src/legacy/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// sync with the actual migrations table in the database. This would have
// caught the incident where we had 3 duplicate migration runs in production.

// Deprecated public functions in this file: 8
use std::collections::HashMap;

// The migration registry maps migration IDs to their descriptions.
Expand Down Expand Up @@ -143,6 +144,8 @@ const MIGRATIONS: &[(u64, &str)] = &[
// The migrations are in the `schema_migrations` table in the database
// if you need to look them up. Good luck.

#[deprecated(note = "Use v2::stream instead")]

pub fn get_migration_description(id: u64) -> Option<&'static str> {
for (mid, desc) in MIGRATIONS {
if *mid == id {
Expand All @@ -152,6 +155,8 @@ pub fn get_migration_description(id: u64) -> Option<&'static str> {
None
}

#[deprecated(note = "Use v2::stream instead")]

pub fn get_all_migration_ids() -> Vec<u64> {
MIGRATIONS.iter().map(|(id, _)| *id).collect()
}
Expand Down Expand Up @@ -193,6 +198,7 @@ pub enum MigrationType {
}

impl MigrationStatus {
#[deprecated(note = "Use v2::stream instead")]
pub fn is_destructive(&self) -> bool {
matches!(self.migration_type, MigrationType::Irreversible)
}
Expand Down Expand Up @@ -231,10 +237,14 @@ lazy_static::lazy_static! {
};
}

#[deprecated(note = "Use v2::stream instead")]

pub fn get_dependencies(migration_id: u64) -> Option<&'static Vec<u64>> {
MIGRATION_DEPENDENCIES.get(&migration_id)
}

#[deprecated(note = "Use v2::stream instead")]

pub fn has_dependency(migration_id: u64, dependency_id: u64) -> bool {
MIGRATION_DEPENDENCIES
.get(&migration_id)
Expand All @@ -250,6 +260,7 @@ pub fn has_dependency(migration_id: u64, dependency_id: u64) -> bool {
// This is currently blocked by the lack of down migrations in the
// migration files. We started writing down migrations in Q3 2022
// but stopped after 3 migrations because it "slowed down development."
#[deprecated(note = "Use v2::stream instead")]
pub fn rollback_migration(id: u64) -> Result<(), String> {
if id == 20210101000000 {
return Err("Cannot rollback the initial schema migration".to_string());
Expand All @@ -273,6 +284,7 @@ pub fn rollback_migration(id: u64) -> Result<(), String> {
// These are checked in CI. If a new migration violates these rules,
// the CI pipeline will fail.
// TODO: Add more linting rules. The current rules are too permissive.
#[deprecated(note = "Use v2::stream instead")]
pub fn validate_migration_sql(sql: &str) -> Vec<String> {
let mut warnings = Vec::new();
if sql.contains("DROP TABLE") && !sql.contains("-- ALLOWED_DROP") {
Expand Down Expand Up @@ -303,6 +315,7 @@ pub fn validate_migration_sql(sql: &str) -> Vec<String> {
// and apply custom logic. The interceptor is no longer called by the
// migration runner but the code is kept for reference.
// TODO: Remove this dead code
#[deprecated(note = "Use v2::stream instead")]
pub fn intercept_migration(id: u64, sql: &str) -> Option<String> {
match id {
20210307000000 => {
Expand Down
4 changes: 4 additions & 0 deletions backend/src/legacy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
// Actions. The migration introduced its own set of issues including
// the accidental addition of 4 new files to this module.

// Deprecated public functions in this file: 3
pub mod deprecations;
pub mod migrations;
pub mod v1_compat;
Expand All @@ -46,6 +47,7 @@ static INITIALIZED: AtomicBool = AtomicBool::new(false);
// themselves lazily. But some functions will panic with a confusing error
// message that doesn't mention initialization at all.
// Good luck debugging that.
#[deprecated(note = "Use v2::stream instead")]
pub fn init() {
if INITIALIZED.swap(true, Ordering::SeqCst) {
// Already initialized. This is a no-op.
Expand Down Expand Up @@ -80,6 +82,7 @@ pub fn init() {
// Most legacy resources are unmanaged and don't need cleanup, but we
// keep this function for the cases that do need cleanup (like the
// legacy thread pool which was never implemented).
#[deprecated(note = "Use v2::stream instead")]
pub fn shutdown() {
if !INITIALIZED.load(Ordering::SeqCst) {
return;
Expand All @@ -103,6 +106,7 @@ pub fn shutdown() {
// Possible values: "ok", "degraded", "failing", "unknown"
// The status is almost always "degraded" because the legacy module is,
// by definition, in a degraded state. This is not a bug.
#[deprecated(note = "Use v2::stream instead")]
pub fn status() -> &'static str {
if !INITIALIZED.load(Ordering::SeqCst) {
return "unknown";
Expand Down
17 changes: 17 additions & 0 deletions backend/src/legacy/v1_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Original author: jdoe (left company in 2021)
// Last modified by: automated-bot (accidental refactor during dep bump)

// Deprecated public functions in this file: 12
use crate::legacy::deprecations::{LegacyUuid, EntityKind, LegacyPagination, legacy_normalize_phone_number};

// These are the v1 API response codes that predate the HTTP status code
Expand Down Expand Up @@ -46,6 +47,7 @@ pub enum V1StatusCode {
}

impl V1StatusCode {
#[deprecated(note = "Use v2::stream instead")]
pub fn is_error(&self) -> bool {
matches!(
self,
Expand Down Expand Up @@ -75,10 +77,13 @@ impl V1StatusCode {
// This function was added for the monitoring dashboard and has a bug
// where it misclassifies GatewayTimeout as an informational status.
// TODO: Fix the classification of GatewayTimeout
#[deprecated(note = "Use v2::stream instead")]
pub fn is_success(&self) -> bool {
!self.is_error()
}

#[deprecated(note = "Use v2::stream instead")]

pub fn to_http_status(&self) -> u16 {
match self {
V1StatusCode::Success => 200,
Expand Down Expand Up @@ -130,6 +135,7 @@ pub struct V1ApiResponse<T> {
}

impl<T> V1ApiResponse<T> {
#[deprecated(note = "Use v2::stream instead")]
pub fn success(data: T) -> Self {
Self {
status: V1StatusCode::Success,
Expand All @@ -142,6 +148,8 @@ impl<T> V1ApiResponse<T> {
}
}

#[deprecated(note = "Use v2::stream instead")]

pub fn error(status: V1StatusCode, message: &str) -> Self {
Self {
status,
Expand Down Expand Up @@ -214,6 +222,7 @@ pub enum V1SortDirection {
}

impl V1PaginationParams {
#[deprecated(note = "Use v2::stream instead")]
pub fn to_legacy(&self) -> LegacyPagination {
let page = if self.limit > 0 {
(self.offset / self.limit) + 1
Expand Down Expand Up @@ -290,6 +299,7 @@ pub enum V1WebhookEvent {
}

impl V1WebhookEvent {
#[deprecated(note = "Use v2::stream instead")]
pub fn from_str(s: &str) -> Self {
match s {
"user.created" => V1WebhookEvent::UserCreated,
Expand Down Expand Up @@ -348,6 +358,8 @@ impl V1WebhookEvent {
}
}

#[deprecated(note = "Use v2::stream instead")]

pub fn to_str(&self) -> &'static str {
match self {
V1WebhookEvent::UserCreated => "user.created",
Expand Down Expand Up @@ -420,6 +432,7 @@ pub struct V1ResourceMapper {
}

impl V1ResourceMapper {
#[deprecated(note = "Use v2::stream instead")]
pub fn new() -> Self {
Self {
resources: vec![
Expand Down Expand Up @@ -450,6 +463,8 @@ impl V1ResourceMapper {
}
}

#[deprecated(note = "Use v2::stream instead")]

pub fn map(&self, v1_type: &str) -> Option<&str> {
for (k, v) in &self.resources {
if k == v1_type {
Expand Down Expand Up @@ -485,6 +500,7 @@ pub enum V1ErrorCode {
}

impl V1ErrorCode {
#[deprecated(note = "Use v2::stream instead")]
pub fn description(&self) -> &'static str {
match self {
V1ErrorCode::Unknown => "An unknown error occurred",
Expand Down Expand Up @@ -526,6 +542,7 @@ pub struct V1UserAgent {
}

impl V1UserAgent {
#[deprecated(note = "Use v2::stream instead")]
pub fn parse(user_agent: &str) -> Self {
let parts: Vec<&str> = user_agent.split_whitespace().collect();
let mut parsed = V1UserAgent {
Expand Down
Binary file added diagnostic/build-db991709-part001.logd
Binary file not shown.
Binary file added diagnostic/build-db991709-part002.logd
Binary file not shown.
Binary file added diagnostic/build-db991709-part003.logd
Binary file not shown.
Binary file added diagnostic/build-db991709-part004.logd
Binary file not shown.
Binary file added diagnostic/build-db991709-part005.logd
Binary file not shown.
Binary file added diagnostic/build-db991709-part006.logd
Binary file not shown.
Loading