1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! Izta - Rust Asynchronous Task Scheduler
//!
//! Izta is a drop-in asynchronous job queue for Rust.
//! It is designed to run in the vast majority of Rust applications without changes
//! to software architecture or system infrastructure.
//! It can run inside your application process as a separate thread or by itself on a separate server.
//! Multiple instances may run concurrently to execute tasks in parallel.
//! Izta also implements named queues, so that tasks in one queue can be processed by Izta instance A and those
//! in another queue by Izta instance B - allowing busy queues to be scaled out separately from others.
//! Currently, Postgres is the only supported backend.
//!
//! # Examples
//! Before starting the job queue, the jobs themselves need to be defined. Any struct that
//! implements the [`Job`] (see [`Job`] documentation for more details), `Serialize` and
//! `Deserialize` traits are valid Job types.
//!
//! Here's an example of a job that simply divides two numbers together:
//!
//! ```rust
//! #[macro_use] extern crate serde;
//! use izta::job::Job;
//!
//! // Jobs can be any type that implements the Job, Serialize and Deserialize traits
//! #[derive(Serialize, Deserialize)]
//! struct DivideJob {
//!     a: i64,
//!     b: i64,
//! }
//!
//! // Jobs must have a serializable error type. Could be `()` for jobs that always succeed
//! #[derive(Serialize, Deserialize)]
//! enum DivideJobErr {
//!     DivideByZero,
//! }
//!
//! impl Job for DivideJob {
//!     // Specify the result and error types
//!     type R = i64;
//!     type E = DivideJobErr;
//!
//!     // All jobs must have a UUID
//!     const UUID: &'static str = "74f3a15b-75c0-4889-9546-63b02ff304e4";
//!
//!     const MAX_ATTEMPTS: usize = 3;
//!
//!     // Job logic - return an `Err` for errors and `Ok` if successful.
//!     fn run(&self) -> Result<Self::R, Self::E> {
//!         if self.b == 0 {
//!             return Err(DivideJobErr::DivideByZero);
//!         }
//!         Ok(self.a / self.b)
//!     }
//! }
//! ```
//!
//! With a job defined, we can now create a task runner:
//! ```no_run
//! # #[macro_use] extern crate serde;
//! # use izta::job::Job;
//! #
//! # // Jobs can be any type that implements the Job, Serialize and Deserialize traits
//! # #[derive(Serialize, Deserialize)]
//! # struct DivideJob {
//! #     a: i64,
//! #     b: i64,
//! # }
//! #
//! # // Jobs must have a serializable error type. Could be `()` for jobs that always succeed
//! # #[derive(Serialize, Deserialize)]
//! # enum DivideJobErr {
//! #     DivideByZero,
//! # }
//! #
//! # impl Job for DivideJob {
//! #     // Specify the result and error types
//! #     type R = i64;
//! #     type E = DivideJobErr;
//! #
//! #     // All jobs must have a UUID
//! #     const UUID: &'static str = "74f3a15b-75c0-4889-9546-63b02ff304e4";
//! #
//! #     const MAX_ATTEMPTS: usize = 3;
//! #
//! #     // Job logic - return an `Err` for errors and `Ok` if successful.
//! #     fn run(&self) -> Result<Self::R, Self::E> {
//! #         if self.b == 0 {
//! #           return Err(DivideJobErr::DivideByZero);
//! #         }
//! #         Ok(self.a / self.b)
//! #     }
//! # }
//! use izta::process_jobs;
//! use izta::runner::Runner;
//!
//! let runner = Runner::new(
//!     process_jobs!(DivideJob),
//!    "postgres://izta:password@localhost:5432/izta_test",
//!    "tasks",
//!    vec![],
//! );
//! ```
//!
//! Defining and adding tasks is easy with [`TaskReq::new`]:
//! ```no_run
//! # #[macro_use] extern crate serde;
//! # use izta::job::Job;
//! #
//! # // Jobs can be any type that implements the Job, Serialize and Deserialize traits
//! # #[derive(Serialize, Deserialize)]
//! # struct DivideJob {
//! #     a: i64,
//! #     b: i64,
//! # }
//! #
//! # // Jobs must have a serializable error type. Could be `()` for jobs that always succeed
//! # #[derive(Serialize, Deserialize)]
//! # enum DivideJobErr {
//! #     DivideByZero,
//! # }
//! #
//! # impl Job for DivideJob {
//! #     // Specify the result and error types
//! #     type R = i64;
//! #     type E = DivideJobErr;
//! #
//! #     // All jobs must have a UUID
//! #     const UUID: &'static str = "74f3a15b-75c0-4889-9546-63b02ff304e4";
//! #
//! #     const MAX_ATTEMPTS: usize = 3;
//! #
//! #     // Job logic - return an `Err` for errors and `Ok` if successful.
//! #     fn run(&self) -> Result<Self::R, Self::E> {
//! #         if self.b == 0 {
//! #           return Err(DivideJobErr::DivideByZero);
//! #         }
//! #         Ok(self.a / self.b)
//! #     }
//! # }
//! # use izta::process_jobs;
//! # use izta::runner::Runner;
//! # let runner = Runner::new(
//! #     process_jobs!(DivideJob),
//! #    "postgres://izta:password@localhost:5432/izta_test",
//! #    "tasks",
//! #    vec![],
//! # );
//! use izta::task::task_req::TaskReq;
//!
//! let task_req = TaskReq::new(DivideJob { a: 1, b: 2 });
//! runner.add_task(&task_req);
//! ```
//!
//! Starting the task runner will begin executing tasks
//! ```no_run
//! # #[macro_use] extern crate serde;
//! # use izta::job::Job;
//! #
//! # // Jobs can be any type that implements the Job, Serialize and Deserialize traits
//! # #[derive(Serialize, Deserialize)]
//! # struct DivideJob {
//! #     a: i64,
//! #     b: i64,
//! # }
//! #
//! # // Jobs must have a serializable error type. Could be `()` for jobs that always succeed
//! # #[derive(Serialize, Deserialize)]
//! # enum DivideJobErr {
//! #     DivideByZero,
//! # }
//! #
//! # impl Job for DivideJob {
//! #     // Specify the result and error types
//! #     type R = i64;
//! #     type E = DivideJobErr;
//! #
//! #     // All jobs must have a UUID
//! #     const UUID: &'static str = "74f3a15b-75c0-4889-9546-63b02ff304e4";
//! #
//! #     const MAX_ATTEMPTS: usize = 3;
//! #
//! #     // Job logic - return an `Err` for errors and `Ok` if successful.
//! #     fn run(&self) -> Result<Self::R, Self::E> {
//! #         if self.b == 0 {
//! #           return Err(DivideJobErr::DivideByZero);
//! #         }
//! #         Ok(self.a / self.b)
//! #     }
//! # }
//! # use izta::process_jobs;
//! # use izta::runner::Runner;
//! # let runner = Runner::new(
//! #     process_jobs!(DivideJob),
//! #    "postgres://izta:password@localhost:5432/izta_test",
//! #    "tasks",
//! #    vec![],
//! # );
//! # use izta::task::task_req::TaskReq;
//! #
//! # let task_req = TaskReq::new(DivideJob { a: 1, b: 2 });
//! # runner.add_task(&task_req);
//! runner.start();
//! ```
//!
//! Of course, it's possible to add new tasks after the task runner has been started.
//! Running `start()` multiple times will spawn multiple instances of the task runner that will
//! execute tasks in parallel.
//!
//! [`Job`]: job/trait.Job.html
//! [`TaskReq::new`]: job/struct.TaskReq.html#method_new
pub mod cron;
mod establish_connection;
pub mod job;
pub mod runner;
mod supervised_thread;
pub mod task;
mod unix_time;

#[macro_use]
extern crate serde;

pub use serde_json;