def test_works(self): with open(self.path, 'w') as f: json.dump({'A': 'a'}, f) r = file_reader.FileReaderThread(self.path, 0.1) r.start() try: self.assertEqual(r.last_value, {'A': 'a'}) # Change the file. Expect possible conflict on Windows. attempt = 0 bytes_json = json.dumps({'B': 'b'}).encode('utf-8') while True: try: file_path.atomic_replace(self.path, bytes_json) break except OSError: attempt += 1 if attempt == 20: self.fail('Cannot replace the file, giving up') time.sleep(0.05) # Give some reasonable time for the reader thread to pick up the change. # This test will flake if for whatever reason OS thread scheduler is # lagging for more than 2 seconds. time.sleep(2) self.assertEqual(r.last_value, {'B': 'b'}) finally: r.stop()
def test_atomic_replace_existing_file(self): path = os.path.join(self.tempdir, 'existing_file') with open(path, 'wb') as f: f.write('existing body') file_path.atomic_replace(path, 'new body') with open(path, 'rb') as f: self.assertEqual('new body', f.read()) self.assertEqual([u'existing_file'], os.listdir(self.tempdir))
def _dump(self): """Attempts to rewrite the file, retrying a bunch of times. Returns: True to carry on, False to exit the thread. """ try: blob = json.dumps(self._producer_callback(), sort_keys=True, indent=2, separators=(',', ': ')) except Exception: logging.exception('Unexpected exception in the callback') return True if blob == self._last_dumped_blob: return True # already have it on disk logging.info('Updating %s', self._path) # On Windows the file may be locked by reading process. Don't freak out, # just retry a bit later. attempts = 100 while True: try: file_path.atomic_replace(self._path, blob) self._last_dumped_blob = blob return True # success! except (IOError, OSError) as e: logging.error('Failed to update the file: %s', e) if not attempts: logging.error( 'Failed to update the file %s after many attempts, giving up', self._path) return True attempts -= 1 if not self._wait(0.05): return False
def test_atomic_replace_new_file(self): path = os.path.join(self.tempdir, 'new_file') file_path.atomic_replace(path, 'blah') with open(path, 'rb') as f: self.assertEqual('blah', f.read()) self.assertEqual([u'new_file'], os.listdir(self.tempdir))