source: trunk/src/allmydata/monitor.py

Last change on this file was 1cfe843d, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-22T23:40:25Z

more python2 removal

  • Property mode set to 100644
File size: 4.3 KB
Line 
1"""
2Manage status of long-running operations.
3
4Ported to Python 3.
5"""
6
7from zope.interface import Interface, implementer
8from allmydata.util import observer
9
10
11class IMonitor(Interface):
12    """I manage status, progress, and cancellation for long-running operations.
13
14    Whoever initiates the operation should create a Monitor instance and pass
15    it into the code that implements the operation. That code should
16    periodically check in with the Monitor, perhaps after each major unit of
17    work has been completed, for two purposes.
18
19    The first is to inform the Monitor about progress that has been made, so
20    that external observers can be reassured that the operation is proceeding
21    normally. If the operation has a well-known amount of work to perform,
22    this notification should reflect that, so that an ETA or 'percentage
23    complete' value can be derived.
24
25    The second purpose is to check to see if the operation has been
26    cancelled. The impatient observer who no longer wants the operation to
27    continue will inform the Monitor; the next time the operation code checks
28    in, it should notice that the operation has been cancelled, and wrap
29    things up. The same monitor can be passed to multiple operations, all of
30    which may check for cancellation: this pattern may be simpler than having
31    the original caller keep track of subtasks and cancel them individually.
32    """
33
34    # the following methods are provided for the operation code
35
36    def is_cancelled():
37        """Returns True if the operation has been cancelled. If True,
38        operation code should stop creating new work, and attempt to stop any
39        work already in progress."""
40
41    def raise_if_cancelled():
42        """Raise OperationCancelledError if the operation has been cancelled.
43        Operation code that has a robust error-handling path can simply call
44        this periodically."""
45
46    def set_status(status):
47        """Sets the Monitor's 'status' object to an arbitrary value.
48        Different operations will store different sorts of status information
49        here. Operation code should use get+modify+set sequences to update
50        this."""
51
52    def get_status():
53        """Return the status object. If the operation failed, this will be a
54        Failure instance."""
55
56    def finish(status):
57        """Call this when the operation is done, successful or not. The
58        Monitor's lifetime is influenced by the completion of the operation
59        it is monitoring. The Monitor's 'status' value will be set with the
60        'status' argument, just as if it had been passed to set_status().
61        This value will be used to fire the Deferreds that are returned by
62        when_done().
63
64        Operations that fire a Deferred when they finish should trigger this
65        with d.addBoth(monitor.finish)"""
66
67    # the following methods are provided for the initiator of the operation
68
69    def is_finished():
70        """Return a boolean, True if the operation is done (whether
71        successful or failed), False if it is still running."""
72
73    def when_done():
74        """Return a Deferred that fires when the operation is complete. It
75        will fire with the operation status, the same value as returned by
76        get_status()."""
77
78    def cancel():
79        """Cancel the operation as soon as possible. is_cancelled() will
80        start returning True after this is called."""
81
82    #   get_status() is useful too, but it is operation-specific
83
84
85class OperationCancelledError(Exception):
86    pass
87
88
89@implementer(IMonitor)
90class Monitor(object):
91
92    def __init__(self):
93        self.cancelled = False
94        self.finished = False
95        self.status = None
96        self.observer = observer.OneShotObserverList()
97
98    def is_cancelled(self):
99        return self.cancelled
100
101    def raise_if_cancelled(self):
102        if self.cancelled:
103            raise OperationCancelledError()
104
105    def is_finished(self):
106        return self.finished
107
108    def when_done(self):
109        return self.observer.when_fired()
110
111    def cancel(self):
112        self.cancelled = True
113
114    def finish(self, status_or_failure):
115        self.set_status(status_or_failure)
116        self.finished = True
117        self.observer.fire(status_or_failure)
118        return status_or_failure
119
120    def get_status(self):
121        return self.status
122    def set_status(self, status):
123        self.status = status
Note: See TracBrowser for help on using the repository browser.