Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: appengine/swarming/swarming_bot/bot_code/file_reader.py

Issue 2024313003: Send authorization headers when calling Swarming backend. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@master
Patch Set: extract into separate function Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file.
4
5 import json
6 import logging
7 import Queue
8 import threading
9 import time
10
11
12 class FatalReadError(Exception):
13 """Raised by 'FileReaderThread.start' if it can't read the file."""
14
15
16 class FileReaderThread(object):
17 """Represents a thread that periodically rereads file from disk.
18
19 Used by task_runner to read authentication headers generated by bot_main.
20
21 Uses JSON for serialization.
22
23 The instance is not reusable (i.e. once stopped, cannot be started again).
24 """
25
26 def __init__(self, path, interval_sec=60, max_attempts=100):
27 self._path = path
28 self._interval_sec = interval_sec
29 self._max_attempts = max_attempts
30 self._thread = None
31 self._signal = Queue.Queue()
32 self._lock = threading.Lock()
33 self._last_value = None
34
35 def start(self):
36 """Starts the thread that periodically rereads the value.
37
38 Once 'start' returns, 'last_value' can be used to grab the read value. It
39 will be kept in-sync with the contents of the file until 'stop' is called.
40
41 Raises:
42 FatalReadError is the file cannot be read even after many retries.
43 """
44 assert self._thread is None
45 self._read() # initial read
46 self._thread = threading.Thread(
47 target=self._run, name='FileReaderThread %s' % self._path)
48 self._thread.daemon = True
49 self._thread.start()
50
51 def stop(self):
52 """Stops the reading thread (if it is running)."""
53 if not self._thread:
54 return
55 self._signal.put(None)
56 self._thread.join(60) # don't wait forever
57 if self._thread.is_alive():
58 logging.error('FileReaderThread failed to terminate in time')
59
60 @property
61 def last_value(self):
62 """Last read value."""
63 with self._lock:
64 return self._last_value
65
66 def _read(self):
67 attempts = self._max_attempts
68 while True:
69 try:
70 with open(self._path, 'rb') as f:
71 body = json.load(f)
72 with self._lock:
73 self._last_value = body
74 return # success!
75 except (OSError, IOError, ValueError) as e:
M-A Ruel 2016/06/06 21:18:36 IOError, OSError, ValueError
Vadim Sh. 2016/06/06 22:17:09 Done.
76 last_error = 'Failed to read auth headers from %s: %s' % (self._path, e)
77 attempts -= 1
78 if not attempts:
79 raise FatalReadError(last_error)
80 time.sleep(0.05)
M-A Ruel 2016/06/06 21:18:36 I'd prefer using: self._signal.get(timeout=0.05)
Vadim Sh. 2016/06/06 22:17:09 Done.
81
82 def _run(self):
83 while True:
84 try:
85 self._signal.get(timeout=self._interval_sec)
86 return # the stop signal received, quit the thread
87 except Queue.Empty:
88 try:
89 self._read()
90 except FatalReadError as e:
91 # Log the error and simply keep last read value as it was. 'start'
92 # makes sure to read it at least once.
93 logging.error('Can\'t reread the file: %s', e)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698