Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
JobScheduler.cs
1using System;
3using System.Threading.Tasks;
4using Waher.Content;
10using Waher.Things;
11
12namespace Waher.Jobs
13{
17 public class JobScheduler : IModule
18 {
19 private static Scheduler scheduler = null;
20 private bool disposeScheduler = false;
21
25 public JobScheduler()
26 {
27 }
28
32 public static Scheduler Scheduler => scheduler;
33
37 public async Task Start()
38 {
39 if (scheduler is null)
40 {
41 if (Types.TryGetModuleParameter("Scheduler", out scheduler))
42 this.disposeScheduler = false;
43 else
44 {
45 scheduler = new Scheduler();
46 this.disposeScheduler = true;
47 }
48 }
49
50 foreach (INode Node in await JobSource.Root.ChildNodes)
51 {
52 if (Node is Job Job)
53 await Schedule(Job, false);
54 }
55 }
56
60 public Task Stop()
61 {
62 if (this.disposeScheduler)
63 scheduler?.Dispose();
64
65 scheduler = null;
66
67 return Task.CompletedTask;
68 }
69
75 public static async Task Schedule(Job Job, bool OnlyIfDifferent)
76 {
77 using Semaphore Semaphore = await Semaphores.BeginWrite("Jobs." + Job.NodeId);
78 JobSchedule Schedule;
79
80 if (!Job.ExecutionTime.HasValue)
81 return;
82
83 lock (scheduledJobs)
84 {
85 if (scheduledJobs.TryGetValue(Job.NodeId, out Schedule))
86 {
87 if (OnlyIfDifferent &&
88 Job.ExecutionTime == Schedule.ExecutionTime &&
89 Job.Period == Schedule.Period &&
90 Job.BurstInterval == Schedule.BurstInterval &&
91 Job.BurstCount == Schedule.BurstCount &&
92 Schedule.ScheduledExecutionTime.HasValue)
93 {
94 return;
95 }
96
97 if (Schedule.ScheduledExecutionTime.HasValue)
98 {
99 scheduler.Remove(Schedule.ScheduledExecutionTime.Value);
100 Schedule.ScheduledExecutionTime = null;
101 }
102
103 Schedule.Job = Job;
104 Schedule.ExecutionTime = Job.ExecutionTime;
105 Schedule.Period = Job.Period;
106 Schedule.BurstInterval = Job.BurstInterval;
107 Schedule.BurstCount = Job.BurstCount;
108 Schedule.BurstCountLeft = Job.BurstCount;
109 }
110 else
111 {
112 scheduledJobs[Job.NodeId] = Schedule = new JobSchedule()
113 {
114 Job = Job,
115 ExecutionTime = Job.ExecutionTime,
116 Period = Job.Period,
117 BurstInterval = Job.BurstInterval,
118 BurstCount = Job.BurstCount,
119 BurstCountLeft = Job.BurstCount
120 };
121 }
122 }
123
124 await Schedule.Next(true);
125 }
126
127 private static readonly Dictionary<string, JobSchedule> scheduledJobs = new Dictionary<string, JobSchedule>();
128
129 private class JobSchedule
130 {
131 public Job Job;
132 public DateTime? ScheduledExecutionTime = null;
133 public DateTime? ExecutionTime = null;
134 public Duration? Period = null;
135 public Duration? BurstInterval = null;
136 public int BurstCount = 1;
137 public int BurstCountLeft = 1;
138
139 public async Task<DateTime?> GetNextFreeTime(bool Reschedule)
140 {
141 if (!this.ExecutionTime.HasValue)
142 return null;
143
144 DateTime TP = this.ExecutionTime.Value;
145 DateTime Now = DateTime.UtcNow;
146
147 if (!this.Period.HasValue && !this.BurstInterval.HasValue)
148 {
149 if (Reschedule)
150 {
151 if (TP.ToUniversalTime() < Now)
152 return Now;
153 else
154 return TP;
155 }
156 else
157 {
158 await this.Job.ExecutionTimeUpdated(null);
159 return null;
160 }
161 }
162
163 bool Updated = false;
164
165 do
166 {
167 if (this.BurstInterval.HasValue)
168 {
169 if (this.BurstCountLeft < this.BurstCount)
170 TP += (this.BurstCount - this.BurstCountLeft) * this.BurstInterval.Value;
171
172 while (
173 this.BurstCountLeft > 0 &&
174 TP.ToUniversalTime() < Now)
175 {
176 TP += this.BurstInterval.Value;
177 this.BurstCountLeft--;
178 }
179 }
180
181 if (TP.ToUniversalTime() >= Now)
182 {
183 if (Updated)
184 await this.Job.ExecutionTimeUpdated(TP);
185
186 return TP;
187 }
188
189 if (!this.Period.HasValue || this.Period.Value <= Duration.Zero)
190 {
191 await this.Job.ExecutionTimeUpdated(null);
192 return null;
193 }
194
195 TP = this.ExecutionTime.Value + this.Period.Value;
196 this.ExecutionTime = TP;
197 this.BurstCountLeft = this.BurstCount;
198 Updated = true;
199 }
200 while (TP.ToUniversalTime() < Now);
201
202 await this.Job.ExecutionTimeUpdated(TP);
203
204 return TP;
205 }
206
207 public async Task ExecuteJob(object _)
208 {
209 using Semaphore Semaphore = await Semaphores.BeginWrite("Jobs." + this.Job.NodeId);
210
211 try
212 {
213 await this.Job.ExecuteJob(await Translator.GetDefaultLanguageAsync());
214 await this.Job.RemoveErrorAsync("ExecutionError");
215 }
216 catch (Exception ex)
217 {
218 await this.Job.LogErrorAsync("ExecutionError", ex.Message);
219 }
220 finally
221 {
222 await this.Next(false);
223 }
224 }
225
226 public async Task Next(bool Reschedule)
227 {
228 DateTime? Next = await this.GetNextFreeTime(Reschedule);
229
230 if (Next.HasValue)
231 this.ScheduledExecutionTime = scheduler?.Add(Next.Value, this.ExecuteJob, null);
232 else
233 {
234 this.ScheduledExecutionTime = null;
235
236 lock (scheduledJobs)
237 {
238 scheduledJobs.Remove(this.Job.NodeId);
239 }
240 }
241 }
242 }
243
249 public static async Task<bool> Remove(Job Job)
250 {
251 using Semaphore Semaphore = await Semaphores.BeginWrite("Jobs." + Job.NodeId);
252
253 lock (scheduledJobs)
254 {
255 if (!scheduledJobs.TryGetValue(Job.NodeId, out JobSchedule Schedule))
256 return false;
257
258 if (Schedule.ScheduledExecutionTime.HasValue)
259 {
260 scheduler.Remove(Schedule.ScheduledExecutionTime.Value);
261 Schedule.ScheduledExecutionTime = null;
262 }
263
264 return scheduledJobs.Remove(Job.NodeId);
265 }
266 }
267 }
268}
Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
Definition: JobNode.cs:695
virtual Task LogErrorAsync(string Body)
Logs an error message on the node.
Definition: JobNode.cs:193
virtual Task< bool > RemoveErrorAsync()
Removes error messages with an empty event ID from the node.
Definition: JobNode.cs:358
string NodeId
ID of node.
Definition: JobNode.cs:143
Module that manages the scheduling and execution of jobs.
Definition: JobScheduler.cs:18
async Task Start()
Starts the module.
Definition: JobScheduler.cs:37
static Scheduler Scheduler
Scheduler used to schedule jobs.
Definition: JobScheduler.cs:32
static async Task< bool > Remove(Job Job)
Removes any scheduled activity for the job.
JobScheduler()
Module that manages the scheduling and execution of jobs.
Definition: JobScheduler.cs:25
Task Stop()
Stops the module.
Definition: JobScheduler.cs:60
static async Task Schedule(Job Job, bool OnlyIfDifferent)
Checks the schedule of a job.
Definition: JobScheduler.cs:75
Defines the Jobs data source. This data source contains a tree structure of jobs of nodes
Definition: JobSource.cs:20
static Root Root
Root node.
Definition: JobSource.cs:215
Represents a job.
Definition: Job.cs:21
Duration? Period
Gets or sets the scheduled execution time of the job.
Definition: Job.cs:56
int BurstCount
Number of executions each period.
Definition: Job.cs:69
Duration? BurstInterval
Gets or sets the scheduled execution time of the job.
Definition: Job.cs:82
DateTime? ExecutionTime
Gets or sets the scheduled execution time of the job.
Definition: Job.cs:43
Task ExecuteJob()
Executes the job.
Definition: Job.cs:201
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:15
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Definition: Types.cs:607
Basic access point for runtime language localization.
Definition: Translator.cs:16
static async Task< Language > GetDefaultLanguageAsync()
Gets the default language.
Definition: Translator.cs:223
Represents a named semaphore, i.e. an object, identified by a name, that allows single concurrent wri...
Definition: Semaphore.cs:19
Static class of application-wide semaphores that can be used to order access to editable objects.
Definition: Semaphores.cs:17
static async Task< Semaphore > BeginWrite(string Key)
Waits until the semaphore identified by Key is ready for writing. Each call to BeginWrite must be fo...
Definition: Semaphores.cs:91
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
Definition: Scheduler.cs:14
bool Remove(DateTime When)
Removes an event scheduled for a given point in time.
Definition: Scheduler.cs:186
void Dispose()
IDisposable.Dispose
Definition: Scheduler.cs:34
DateTime Add(DateTime When, Action< object > Callback, object State)
Adds an event.
Definition: Scheduler.cs:54
Interface for late-bound modules loaded at runtime.
Definition: IModule.cs:9
Interface for nodes that are published through the concentrator interface.
Definition: INode.cs:49
Definition: ImplTypes.g.cs:58
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:14
static readonly Duration Zero
Zero value
Definition: Duration.cs:577