blob: ded0ab6bcef366539eb005f37c937888714176f6 [file] [log] [blame]
Nathaniel Manistaf36e1b72015-08-18 01:30:29 +00001# Copyright 2015, Google Inc.
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met:
7#
8# * Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# * Redistributions in binary form must reproduce the above
11# copyright notice, this list of conditions and the following disclaimer
12# in the documentation and/or other materials provided with the
13# distribution.
14# * Neither the name of Google Inc. nor the names of its
15# contributors may be used to endorse or promote products derived from
16# this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30"""State and behavior for operation expiration."""
31
32import time
33
34from grpc.framework.core import _interfaces
Nathaniel Manista69210e52015-09-02 19:24:41 +000035from grpc.framework.core import _utilities
Nathaniel Manistaf36e1b72015-08-18 01:30:29 +000036from grpc.framework.foundation import later
37from grpc.framework.interfaces.base import base
38
39
40class _ExpirationManager(_interfaces.ExpirationManager):
41 """An implementation of _interfaces.ExpirationManager."""
42
43 def __init__(
44 self, commencement, timeout, maximum_timeout, lock, termination_manager,
45 transmission_manager):
46 """Constructor.
47
48 Args:
49 commencement: The time in seconds since the epoch at which the operation
50 began.
51 timeout: A length of time in seconds to allow for the operation to run.
52 maximum_timeout: The maximum length of time in seconds to allow for the
53 operation to run despite what is requested via this object's
54 change_timout method.
55 lock: The operation-wide lock.
56 termination_manager: The _interfaces.TerminationManager for the operation.
57 transmission_manager: The _interfaces.TransmissionManager for the
58 operation.
59 """
60 self._lock = lock
61 self._termination_manager = termination_manager
62 self._transmission_manager = transmission_manager
63 self._commencement = commencement
64 self._maximum_timeout = maximum_timeout
65
66 self._timeout = timeout
67 self._deadline = commencement + timeout
68 self._index = None
69 self._future = None
70
71 def _expire(self, index):
72 def expire():
73 with self._lock:
74 if self._future is not None and index == self._index:
75 self._future = None
76 self._termination_manager.expire()
Nathaniel Manista69210e52015-09-02 19:24:41 +000077 self._transmission_manager.abort(
78 _utilities.Outcome(base.Outcome.Kind.EXPIRED, None, None))
Nathaniel Manistaf36e1b72015-08-18 01:30:29 +000079 return expire
80
81 def start(self):
82 self._index = 0
83 self._future = later.later(self._timeout, self._expire(0))
84
85 def change_timeout(self, timeout):
86 if self._future is not None and timeout != self._timeout:
87 self._future.cancel()
88 new_timeout = min(timeout, self._maximum_timeout)
89 new_index = self._index + 1
90 self._timeout = new_timeout
91 self._deadline = self._commencement + new_timeout
92 self._index = new_index
93 delay = self._deadline - time.time()
94 self._future = later.later(delay, self._expire(new_index))
95 if new_timeout != timeout:
96 self._transmission_manager.timeout(new_timeout)
97
98 def deadline(self):
99 return self._deadline
100
101 def terminate(self):
102 if self._future:
103 self._future.cancel()
104 self._future = None
105 self._deadline_index = None
106
107
108def invocation_expiration_manager(
109 timeout, lock, termination_manager, transmission_manager):
110 """Creates an _interfaces.ExpirationManager appropriate for front-side use.
111
112 Args:
113 timeout: A length of time in seconds to allow for the operation to run.
114 lock: The operation-wide lock.
115 termination_manager: The _interfaces.TerminationManager for the operation.
116 transmission_manager: The _interfaces.TransmissionManager for the
117 operation.
118
119 Returns:
120 An _interfaces.ExpirationManager appropriate for invocation-side use.
121 """
122 expiration_manager = _ExpirationManager(
123 time.time(), timeout, timeout, lock, termination_manager,
124 transmission_manager)
125 expiration_manager.start()
126 return expiration_manager
127
128
129def service_expiration_manager(
130 timeout, default_timeout, maximum_timeout, lock, termination_manager,
131 transmission_manager):
132 """Creates an _interfaces.ExpirationManager appropriate for back-side use.
133
134 Args:
135 timeout: A length of time in seconds to allow for the operation to run. May
136 be None in which case default_timeout will be used.
137 default_timeout: The default length of time in seconds to allow for the
138 operation to run if the front-side customer has not specified such a value
139 (or if the value they specified is not yet known).
140 maximum_timeout: The maximum length of time in seconds to allow for the
141 operation to run.
142 lock: The operation-wide lock.
143 termination_manager: The _interfaces.TerminationManager for the operation.
144 transmission_manager: The _interfaces.TransmissionManager for the
145 operation.
146
147 Returns:
148 An _interfaces.ExpirationManager appropriate for service-side use.
149 """
150 expiration_manager = _ExpirationManager(
151 time.time(), default_timeout if timeout is None else timeout,
152 maximum_timeout, lock, termination_manager, transmission_manager)
153 expiration_manager.start()
154 return expiration_manager