@@ -44,7 +44,8 @@ class QueueRunner(object):
4444 """
4545
4646 def __init__ (self , queue = None , enqueue_ops = None , close_op = None ,
47- cancel_op = None , queue_runner_def = None ):
47+ cancel_op = None , queue_closed_exception_types = None ,
48+ queue_runner_def = None ):
4849 """Create a QueueRunner.
4950
5051 On construction the `QueueRunner` adds an op to close the queue. That op
@@ -61,6 +62,11 @@ def __init__(self, queue=None, enqueue_ops=None, close_op=None,
6162 enqueue_ops: List of enqueue ops to run in threads later.
6263 close_op: Op to close the queue. Pending enqueue ops are preserved.
6364 cancel_op: Op to close the queue and cancel pending enqueue ops.
65+ queue_closed_exception_types: Optional tuple of Exception types that
66+ indicate that the queue has been closed when raised during an enqueue
67+ operation. Defaults to `(tf.errors.OutOfRangeError,)`. Another common
68+ case includes `(tf.errors.OutOfRangeError, tf.errors.CancelledError)`,
69+ when some of the enqueue ops may dequeue from other Queues.
6470 queue_runner_def: Optional `QueueRunnerDef` protocol buffer. If specified,
6571 recreates the QueueRunner from its contents. `queue_runner_def` and the
6672 other arguments are mutually exclusive.
@@ -75,34 +81,50 @@ def __init__(self, queue=None, enqueue_ops=None, close_op=None,
7581 raise ValueError ("queue_runner_def and queue are mutually exclusive." )
7682 self ._init_from_proto (queue_runner_def )
7783 else :
78- self ._init_from_args (queue = queue , enqueue_ops = enqueue_ops ,
79- close_op = close_op , cancel_op = cancel_op )
84+ self ._init_from_args (
85+ queue = queue , enqueue_ops = enqueue_ops ,
86+ close_op = close_op , cancel_op = cancel_op ,
87+ queue_closed_exception_types = queue_closed_exception_types )
8088 # Protect the count of runs to wait for.
8189 self ._lock = threading .Lock ()
8290 self ._runs = 0
8391 # List of exceptions raised by the running threads.
8492 self ._exceptions_raised = []
8593
8694 def _init_from_args (self , queue = None , enqueue_ops = None , close_op = None ,
87- cancel_op = None ):
95+ cancel_op = None , queue_closed_exception_types = None ):
8896 """Create a QueueRunner from arguments.
8997
9098 Args:
9199 queue: A `Queue`.
92100 enqueue_ops: List of enqueue ops to run in threads later.
93101 close_op: Op to close the queue. Pending enqueue ops are preserved.
94102 cancel_op: Op to close the queue and cancel pending enqueue ops.
103+ queue_closed_exception_types: Tuple of exception types, which indicate
104+ the queue has been safely closed.
95105
96106 Raises:
97107 ValueError: If `queue` or `enqueue_ops` are not provided when not
98108 restoring from `queue_runner_def`.
109+ TypeError: If `queue_closed_exception_types` is provided, but is not
110+ a non-empty tuple of error types (subclasses of `tf.errors.OpError`).
99111 """
100112 if not queue or not enqueue_ops :
101113 raise ValueError ("Must provide queue and enqueue_ops." )
102114 self ._queue = queue
103115 self ._enqueue_ops = enqueue_ops
104116 self ._close_op = close_op
105117 self ._cancel_op = cancel_op
118+ if queue_closed_exception_types is not None :
119+ if (not isinstance (queue_closed_exception_types , tuple )
120+ or not queue_closed_exception_types
121+ or not all (issubclass (t , errors .OpError )
122+ for t in queue_closed_exception_types )):
123+ raise TypeError (
124+ "queue_closed_exception_types, when provided, "
125+ "must be a non-empty list of tf.error types, but saw: %s"
126+ % queue_closed_exception_types )
127+ self ._queue_closed_exception_types = queue_closed_exception_types
106128 # Close when no more will be produced, but pending enqueues should be
107129 # preserved.
108130 if self ._close_op is None :
@@ -111,6 +133,11 @@ def _init_from_args(self, queue=None, enqueue_ops=None, close_op=None,
111133 # to unblock everything so we can cleanly exit.
112134 if self ._cancel_op is None :
113135 self ._cancel_op = self ._queue .close (cancel_pending_enqueues = True )
136+ if not self ._queue_closed_exception_types :
137+ self ._queue_closed_exception_types = (errors .OutOfRangeError ,)
138+ else :
139+ self ._queue_closed_exception_types = tuple (
140+ self ._queue_closed_exception_types )
114141
115142 def _init_from_proto (self , queue_runner_def ):
116143 """Create a QueueRunner from `QueueRunnerDef`.
@@ -125,6 +152,13 @@ def _init_from_proto(self, queue_runner_def):
125152 in queue_runner_def .enqueue_op_name ]
126153 self ._close_op = g .as_graph_element (queue_runner_def .close_op_name )
127154 self ._cancel_op = g .as_graph_element (queue_runner_def .cancel_op_name )
155+ self ._queue_closed_exception_types = tuple (
156+ errors .exception_type_from_error_code (code )
157+ for code in queue_runner_def .queue_closed_exception_types )
158+ # Legacy support for old QueueRunnerDefs created before this field
159+ # was added.
160+ if not self ._queue_closed_exception_types :
161+ self ._queue_closed_exception_types = (errors .OutOfRangeError ,)
128162
129163 @property
130164 def queue (self ):
@@ -142,6 +176,10 @@ def close_op(self):
142176 def cancel_op (self ):
143177 return self ._cancel_op
144178
179+ @property
180+ def queue_closed_exception_types (self ):
181+ return self ._queue_closed_exception_types
182+
145183 @property
146184 def exceptions_raised (self ):
147185 """Exceptions raised but not handled by the `QueueRunner` threads.
@@ -185,7 +223,7 @@ def _run(self, sess, enqueue_op, coord=None):
185223 break
186224 try :
187225 sess .run (enqueue_op )
188- except errors . OutOfRangeError :
226+ except self . _queue_closed_exception_types : # pylint: disable=catching-non-exception
189227 # This exception indicates that a queue was closed.
190228 with self ._lock :
191229 self ._runs -= 1
@@ -290,6 +328,9 @@ def to_proto(self):
290328 queue_runner_def .enqueue_op_name .append (enqueue_op .name )
291329 queue_runner_def .close_op_name = self .close_op .name
292330 queue_runner_def .cancel_op_name = self .cancel_op .name
331+ queue_runner_def .queue_closed_exception_types .extend ([
332+ errors .error_code_from_exception_type (cls )
333+ for cls in self ._queue_closed_exception_types ])
293334 return queue_runner_def
294335
295336 @staticmethod
0 commit comments