|
1 | 1 | use std::{
|
| 2 | + cmp, |
2 | 3 | collections::{
|
3 | 4 | BTreeMap,
|
4 | 5 | HashSet,
|
@@ -88,10 +89,7 @@ use model::{
|
88 | 89 | use parking_lot::Mutex;
|
89 | 90 | use sync_types::Timestamp;
|
90 | 91 | use usage_tracking::FunctionUsageTracker;
|
91 |
| -use value::{ |
92 |
| - ResolvedDocumentId, |
93 |
| - TableNamespace, |
94 |
| -}; |
| 92 | +use value::ResolvedDocumentId; |
95 | 93 |
|
96 | 94 | use crate::{
|
97 | 95 | application_function_runner::ApplicationFunctionRunner,
|
@@ -897,51 +895,65 @@ impl<RT: Runtime> ScheduledJobGarbageCollector<RT> {
|
897 | 895 | async fn run(&self, backoff: &mut Backoff) -> anyhow::Result<()> {
|
898 | 896 | loop {
|
899 | 897 | let mut tx = self.database.begin(Identity::system()).await?;
|
900 |
| - let namespace = TableNamespace::by_component_TODO(); |
901 |
| - let now = self.rt.generate_timestamp()?; |
902 |
| - let index_query = Query::index_range(IndexRange { |
903 |
| - index_name: SCHEDULED_JOBS_INDEX_BY_COMPLETED_TS.clone(), |
904 |
| - range: vec![IndexRangeExpression::Gt( |
905 |
| - COMPLETED_TS_FIELD.clone(), |
906 |
| - value::ConvexValue::Null, |
907 |
| - )], |
908 |
| - order: Order::Asc, |
909 |
| - }) |
910 |
| - .limit(*SCHEDULED_JOB_GARBAGE_COLLECTION_BATCH_SIZE); |
911 |
| - let mut query_stream = ResolvedQuery::new(&mut tx, namespace, index_query)?; |
912 |
| - |
| 898 | + let namespaces = tx |
| 899 | + .table_mapping() |
| 900 | + .namespaces_for_name(&SCHEDULED_JOBS_TABLE); |
| 901 | + let mut deleted_jobs = false; |
913 | 902 | let mut next_job_wait = None;
|
914 |
| - let mut jobs_to_delete = vec![]; |
915 |
| - while let Some(doc) = query_stream.next(&mut tx, None).await? { |
916 |
| - let job: ParsedDocument<ScheduledJob> = doc.try_into()?; |
917 |
| - match job.state { |
918 |
| - ScheduledJobState::Success => (), |
919 |
| - ScheduledJobState::Failed(_) => (), |
920 |
| - ScheduledJobState::Canceled => (), |
921 |
| - _ => anyhow::bail!("Scheduled job to be garbage collected has the wrong state"), |
922 |
| - } |
| 903 | + for namespace in namespaces { |
| 904 | + let now = self.rt.generate_timestamp()?; |
| 905 | + let index_query = Query::index_range(IndexRange { |
| 906 | + index_name: SCHEDULED_JOBS_INDEX_BY_COMPLETED_TS.clone(), |
| 907 | + range: vec![IndexRangeExpression::Gt( |
| 908 | + COMPLETED_TS_FIELD.clone(), |
| 909 | + value::ConvexValue::Null, |
| 910 | + )], |
| 911 | + order: Order::Asc, |
| 912 | + }) |
| 913 | + .limit(*SCHEDULED_JOB_GARBAGE_COLLECTION_BATCH_SIZE); |
| 914 | + let mut query_stream = ResolvedQuery::new(&mut tx, namespace, index_query)?; |
| 915 | + |
| 916 | + let mut jobs_to_delete = vec![]; |
| 917 | + while let Some(doc) = query_stream.next(&mut tx, None).await? { |
| 918 | + let job: ParsedDocument<ScheduledJob> = doc.try_into()?; |
| 919 | + match job.state { |
| 920 | + ScheduledJobState::Success => (), |
| 921 | + ScheduledJobState::Failed(_) => (), |
| 922 | + ScheduledJobState::Canceled => (), |
| 923 | + _ => anyhow::bail!( |
| 924 | + "Scheduled job to be garbage collected has the wrong state" |
| 925 | + ), |
| 926 | + } |
923 | 927 |
|
924 |
| - let completed_ts = match job.completed_ts { |
925 |
| - Some(completed_ts) => completed_ts, |
926 |
| - None => { |
927 |
| - anyhow::bail!("Could not get completed_ts of finished scheduled job"); |
928 |
| - }, |
929 |
| - }; |
930 |
| - if completed_ts.add(*SCHEDULED_JOB_RETENTION)? > now { |
931 |
| - next_job_wait = Some(completed_ts.add(*SCHEDULED_JOB_RETENTION)? - now); |
932 |
| - break; |
| 928 | + let completed_ts = match job.completed_ts { |
| 929 | + Some(completed_ts) => completed_ts, |
| 930 | + None => { |
| 931 | + anyhow::bail!("Could not get completed_ts of finished scheduled job"); |
| 932 | + }, |
| 933 | + }; |
| 934 | + if completed_ts.add(*SCHEDULED_JOB_RETENTION)? > now { |
| 935 | + let next_job_wait_ns = completed_ts.add(*SCHEDULED_JOB_RETENTION)? - now; |
| 936 | + next_job_wait = match next_job_wait { |
| 937 | + Some(next_job_wait) => Some(cmp::min(next_job_wait, next_job_wait_ns)), |
| 938 | + None => Some(next_job_wait_ns), |
| 939 | + }; |
| 940 | + break; |
| 941 | + } |
| 942 | + jobs_to_delete.push(job.id()); |
933 | 943 | }
|
934 |
| - jobs_to_delete.push(job.id()); |
935 |
| - } |
936 |
| - if !jobs_to_delete.is_empty() { |
937 |
| - tracing::debug!( |
938 |
| - "Garbage collecting {} finished scheduled jobs", |
939 |
| - jobs_to_delete.len() |
940 |
| - ); |
941 |
| - let mut model = SchedulerModel::new(&mut tx, namespace); |
942 |
| - for job_id in jobs_to_delete { |
943 |
| - model.delete(job_id).await?; |
| 944 | + if !jobs_to_delete.is_empty() { |
| 945 | + tracing::debug!( |
| 946 | + "Garbage collecting {} finished scheduled jobs", |
| 947 | + jobs_to_delete.len() |
| 948 | + ); |
| 949 | + let mut model = SchedulerModel::new(&mut tx, namespace); |
| 950 | + for job_id in jobs_to_delete { |
| 951 | + model.delete(job_id).await?; |
| 952 | + } |
| 953 | + deleted_jobs = true; |
944 | 954 | }
|
| 955 | + } |
| 956 | + if deleted_jobs { |
945 | 957 | self.database
|
946 | 958 | .commit_with_write_source(tx, "scheduled_job_gc")
|
947 | 959 | .await?;
|
|
0 commit comments