]> git.ipfire.org Git - thirdparty/squid.git/blob - src/base/AsyncJobs.dox
Merged from trunk
[thirdparty/squid.git] / src / base / AsyncJobs.dox
1 /**
2 \defgroup AsyncJobs Asynchronous Jobs
3 \ingroup Components
4
5 \section Terminology Terminology
6
7 - \b Job: an AsyncJob object.
8 - \b Creator: the code creating the job. Usually the Initiator.
9 - \b Start: the act of calling AsyncJob::Start with a job pointer.
10 - \b Initiator: the code starting the job. Usually the Creator.
11
12 \section Life Typical life cycle
13
14 -# Creator creates and initializes a job.
15 -# If Initiator expects to communicate with the job after start,
16 then it stores the job pointer
17 -# Initiator starts the job by calling AsyncJob::Start.
18 -# The job's start() method is called. The method usually schedules
19 some I/O or registers to receive some other callbacks.
20 -# The job runs and does what it is supposed to do. This usually involves
21 scheduling I/O, setting timeouts, receiving Comm or Store callbacks, and
22 then notifying Initiator of the final result.
23 -# The job reaches its goal or encounters an error condition.
24 -# The swanSong() method is called.
25 -# The job object is destroyed.
26
27
28 If you want to do something before starting the job, do it in the constructor
29 or some custom method that the job creator will call _before_ calling
30 AsyncJob::Start():
31
32 std::auto_ptr<MyJob> job(new MyJob(...)); // sync/blocking
33 job->prepare(...); // sync/blocking
34 job->prepareSomethingElse(...); // sync/blocking
35 AsyncStart(job.release()); // non-blocking
36
37 If you do not need complex preparations, it is better to do this instead:
38
39 AsyncJob::Start(new MyJob(...));
40
41 Keep in mind that you have no async debugging, cleanup, and protections until
42 you call AsyncJob::Start with a job pointer.
43
44
45 \section Rules Basic rules
46
47 - To start a job, use AsyncJob::Start.
48 Do not start the same job more than once.
49
50 - Never call start() directly. Treat this method as main() in C/C++.
51
52 - Never call swanSong() directly. If you are outside an AsyncCall
53 handler, and want to kill the job, then call deleteThis(). If you are
54 inside an AsyncCall handler, you have several options for job termination:
55
56 -# Call mustStop(reason) for errors that require further processing in
57 the same method(s) chain, below/after the mustStop() call. Efficient.
58
59 -# Throw (via Must or directly) for errors that do not require further
60 processing in the same method(s) chain, below/after the mustStop() call.
61 Inefficient but simple and allows exiting from deeply nested method calls.
62
63 -# Otherwise, just finish the call. Your doneAll() should return true
64 and the job will terminate successfully.
65
66 swanSong() will be called automatically in all of these cases when the
67 job is being terminated. It is a general cleanup method, like a
68 destructor. The only difference is that a destructor must not throw.
69
70
71 - Do not assume swanSong() is called in some perfectly nice job state.
72 The job code or the code it calls may throw at any time after start()
73 was called. The entry may be gone, the Abort may have been called, the
74 fd may have been closed, etc.
75
76
77 - Never call deleteThis() in contexts other than those documented above.
78 It is a hack for the old-style code. You can avoid it and other
79 old-style special precautions altogether if you convert sync calls into
80 async ones. This is especially easy for old-style calls that have only
81 one parameter ("data") or two simple parameters.
82
83
84 - In swanSong, always call swanSong() of the parent, after you are done
85 cleaning up your job. It does not matter whether the [current] parent
86 swanSong() does nothing.
87
88 - You must implement start() and doneAll() methods. These methods may be
89 marked as pure virtual in future releases.
90
91 - In doneAll(), always call doneAll() of the parent. If the parent is not
92 done, you are not done. It does not matter whether the [current] parent
93 doneAll() always returns true.
94
95 - If a job does not have a doneAll() method implemented, it is probably
96 buggy. Any job must know what it wants to accomplish. Please note that
97 doneAll() is for defining the successful termination goal/condition.
98 Errors are handled by mustStop() or throw, as discussed above.
99
100 Similarly, if your doneAll() implementation looks like "return isDone;",
101 you are doing it wrong. Compute the condition directly rather than
102 expecting various job methods to maintain some isDone variable correctly.
103
104
105 - If a job does Comm I/O, it probably needs a Comm closing handler.
106
107 - If a job stores a StoreEntry, it probably needs an entry Abort handler.
108
109 - Ask yourself what the user will see/experience when the job throws,
110 which could happen as early as in the start() method (technically, it
111 can happen even earlier, during job creation and initialization). Are you
112 OK with that?
113
114
115 */