celery/task/
options.rs

1use crate::protocol::MessageContentType;
2
3/// Configuration options pertaining to a task.
4///
5/// These are set at either the app level (pertaining to all registered tasks),
6/// the task level (pertaining to a specific task), or - in some cases - at
7/// the request / signature level (pertaining only to an individual task request).
8///
9/// The order of precedence is determined by how specific the given configuration option is.
10/// That is, options set at the request level have the highest precedence,
11/// followed by options set at the task level, and lastly the app level.
12///
13/// For example, if `time_limit: Some(10)` is set at the app level through the
14/// [`task_time_limit`](crate::CeleryBuilder::task_time_limit) option,
15/// then every task will use a time limit of 10 seconds unless some other time limit is specified in the
16/// [task definition](attr.task.html#parameters) or in a
17/// [task signature](../task/struct.Signature.html#structfield.time_limit) for that task.
18#[derive(Copy, Clone, Default)]
19pub struct TaskOptions {
20    /// Time limit for a task.
21    ///
22    /// If set to `Some(n)`, the task will be interrupted and fail with a
23    /// [`TimeoutError`](error/enum.TaskError.html#variant.TimeoutError)
24    /// if it runs longer than `n` seconds.
25    ///
26    /// This can be set with
27    /// - [`task_time_limit`](crate::CeleryBuilder::task_time_limit) at the app level,
28    /// - [`time_limit`](../attr.task.html#parameters) at the task level, and
29    /// - [`with_time_limit`](crate::task::Signature::with_time_limit) at the request / signature level.
30    ///
31    /// If this option is left unspecified, the default behavior will be to enforce no time limit.
32    ///
33    /// *Note, however, that only non-blocking tasks can be interrupted, so it's important
34    /// to use async functions within task implementations whenever they are available.*
35    pub time_limit: Option<u32>,
36
37    /// The [`time_limit`](TaskOptions::time_limit) option is equivalent to the ["soft time
38    /// limit"](https://docs.celeryproject.org/en/stable/userguide/workers.html#time-limits)
39    /// option when sending tasks to a Python consumer.
40    /// If you desire to set a "hard time limit", use this option.
41    ///
42    /// *Note that this is really only for compatability with Python workers*.
43    /// `time_limit` and `hard_time_limit` are treated the same by Rust workers, and if both
44    /// are set, the minimum of the two will be used.
45    ///
46    /// This can be set with
47    /// - [`task_hard_time_limit`](crate::CeleryBuilder::task_hard_time_limit) at the app level,
48    /// - [`hard_time_limit`](../attr.task.html#parameters) at the task level, and
49    /// - [`with_hard_time_limit`](crate::task::Signature::method.with_hard_time_limit) at the request / signature level.
50    pub hard_time_limit: Option<u32>,
51
52    /// Time in seconds for when the task should expire. The task won’t be
53    /// executed after the expiration time. This can be overridden when calling the task, see
54    /// [`Signature::with_expires`](crate::task::Signature::with_expires) and
55    /// [`Signature::with_expires_in`](crate::task::Signature::with_expires_in).
56    pub expires: Option<std::time::Duration>,
57
58    /// Maximum number of retries for this task.
59    ///
60    /// This can be set with
61    /// - [`task_max_retries`](crate::CeleryBuilder::task_max_retries) at the app level, and
62    /// - [`max_retries`](../attr.task.html#parameters) at the task level.
63    ///
64    /// If this option is left unspecified, the default behavior will be to retry tasks indefinitely.
65    pub max_retries: Option<u32>,
66
67    /// Minimum retry delay (in seconds).
68    ///
69    /// This can be set with
70    /// - [`task_min_retry_delay`](crate::CeleryBuilder::task_min_retry_delay) at the app level, and
71    /// - [`min_retry_delay`](../attr.task.html#parameters) at the task level.
72    ///
73    /// If this option is left unspecified, the default behavior will be to use 0 as the
74    /// minimum. In practice this means the first retry will usually be delayed only a couple hundred milliseconds.
75    /// The delay for subsequent retries will increase exponentially (with random jitter) before
76    /// maxing out at [`max_retry_delay`](TaskOptions::max_retry_delay).
77    pub min_retry_delay: Option<u32>,
78
79    /// Maximum retry delay (in seconds).
80    ///
81    /// This can be set with
82    /// - [`task_max_retry_delay`](crate::CeleryBuilder::task_max_retry_delay) at the app level, and
83    /// - [`max_retry_delay`](../attr.task.html#parameters) at the task level.
84    ///
85    /// If this option is left unspecified, the default behavior will be to cap delays at 1 hour
86    /// (3600 seconds) with some random jitter.
87    pub max_retry_delay: Option<u32>,
88
89    /// Whether or not to retry the task when an [`UnexpectedError`](crate::error::TaskError::UnexpectedError)
90    /// is returned.
91    ///
92    /// This can be set with
93    /// - [`task_retry_for_unexpected`](crate::CeleryBuilder::task_retry_for_unexpected) at the app level, and
94    /// - [`retry_for_unexpected`](../attr.task.html#parameters) at the task level.
95    ///
96    /// If this option is left unspecified, the default behavior will be to retry for these
97    /// errors.
98    pub retry_for_unexpected: Option<bool>,
99
100    /// Whether messages will be acknowledged after the task has been executed or before.
101    ///
102    /// If your tasks are
103    /// [idempotent](https://docs.celeryproject.org/en/stable/glossary.html#term-idempotent)
104    /// then it is recommended that you set this to `true`.
105    ///
106    /// This can be set with
107    /// - [`acks_late`](crate::CeleryBuilder::acks_late) at the app level, and
108    /// - [`acks_late`](../attr.task.html#parameters) at the task level.
109    ///
110    /// If this option is left unspecified, the default behavior will be to ack early.
111    pub acks_late: Option<bool>,
112
113    /// Which serialization format to use for task messages.
114    ///
115    /// This can be set with
116    /// - [`task_content_type`](crate::CeleryBuilder::task_content_type) at the app level, and
117    /// - [`content_type`](../attr.task.html#parameters) at the task level.
118    /// - [`with_content_type`](crate::task::Signature::with_content_type) at the request / signature level.
119    pub content_type: Option<MessageContentType>,
120}
121
122impl TaskOptions {
123    /// Update the fields in `self` with the fields in `other`.
124    pub(crate) fn update(&mut self, other: &TaskOptions) {
125        self.time_limit = self.time_limit.or(other.time_limit);
126        self.hard_time_limit = self.hard_time_limit.or(other.hard_time_limit);
127        self.max_retries = self.max_retries.or(other.max_retries);
128        self.min_retry_delay = self.min_retry_delay.or(other.min_retry_delay);
129        self.max_retry_delay = self.max_retry_delay.or(other.max_retry_delay);
130        self.retry_for_unexpected = self.retry_for_unexpected.or(other.retry_for_unexpected);
131        self.acks_late = self.acks_late.or(other.acks_late);
132        self.content_type = self.content_type.or(other.content_type);
133    }
134
135    /// Override the fields in `other` with the fields in `self`.
136    pub(crate) fn override_other(&self, other: &mut TaskOptions) {
137        other.update(self);
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn test_update() {
147        let mut options = TaskOptions {
148            max_retries: Some(3),
149            acks_late: Some(true),
150            ..Default::default()
151        };
152
153        let other = TaskOptions {
154            time_limit: Some(2),
155            acks_late: Some(false),
156            ..Default::default()
157        };
158
159        options.update(&other);
160        assert_eq!(options.time_limit, Some(2));
161        assert_eq!(options.max_retries, Some(3));
162        assert_eq!(options.acks_late, Some(true));
163    }
164}