diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..56f572b9dc161ed9595e9699216a0adab9177add --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Flamenco Worker changelog + +This file logs the changes that are actually interesting to users (new features, +changed functionality, fixed bugs). + + +## Version 2.0.1 (released 2017-03-31) + +- Registers rendered and copied files with the Manager, so that they can be + shown as "latest render". + + +## Version 2.0 (released 2017-03-29) + +- First release of Pillar-based Flamenco, including this Worker. diff --git a/flamenco_worker/commands.py b/flamenco_worker/commands.py index 8f419d1bfb36c3a6116cf5b9f7c37d07ac434cb6..8417ba0101824a370c9049a61159f1a8a4ccda46 100644 --- a/flamenco_worker/commands.py +++ b/flamenco_worker/commands.py @@ -359,7 +359,7 @@ class CopyFileCommand(AbstractCommand): import shutil shutil.copy(str(src), str(dest)) - + self.worker.output_produced(dest) @command_executor('remove_tree') class RemoveTreeCommand(AbstractCommand): @@ -499,6 +499,7 @@ class BlenderRenderCommand(AbstractSubprocessCommand): re_remaining = attr.ib(init=False) re_status = attr.ib(init=False) re_path_not_found = attr.ib(init=False) + re_file_saved = attr.ib(init=False) def __attrs_post_init__(self): super().__attrs_post_init__() @@ -512,6 +513,7 @@ class BlenderRenderCommand(AbstractSubprocessCommand): r'\| Remaining:((?P<hours>\d+):)?(?P<minutes>\d+):(?P<seconds>\d+)\.(?P<hunds>\d+) ') self.re_status = re.compile(r'\| (?P<status>[^\|]+)\s*$') self.re_path_not_found = re.compile(r"Warning: Path '.*' not found") + self.re_file_saved = re.compile(r"Saved: '(?P<filename>.*)'") def validate(self, settings: dict): import shlex @@ -625,6 +627,11 @@ class BlenderRenderCommand(AbstractSubprocessCommand): activity = line await self.worker.register_task_update(activity=activity) + # See if this line logs the saving of a file. + m = self.re_file_saved.search(line) + if m: + self.worker.output_produced(m.group('filename')) + # Not a render progress line; just log it for now. return '> %s' % line @@ -724,7 +731,10 @@ class MergeProgressiveRendersCommand(AbstractSubprocessCommand): # move output files into the correct spot. await self.move(tmppath / 'merged0001.exr', output) - await self.move(tmppath / 'preview.jpg', output.with_suffix('.jpg')) + # await self.move(tmppath / 'preview.jpg', output.with_suffix('.jpg')) + + # See if this line logs the saving of a file. + self.worker.output_produced(output) async def move(self, src: Path, dst: Path): """Moves a file to another location.""" diff --git a/flamenco_worker/worker.py b/flamenco_worker/worker.py index dd1fb62b195e17c57b98acafe12e3c31e454cb04..08e4bd5291e0064ceaa2edc05f226ef68e236e00 100644 --- a/flamenco_worker/worker.py +++ b/flamenco_worker/worker.py @@ -1,5 +1,6 @@ import asyncio import datetime +import pathlib import typing import attr @@ -302,7 +303,7 @@ class FlamencoWorker: ) elif self.failures_are_acceptable: self._log.warning('Task %s failed, but ignoring it since we are shutting down.', - self.task_id) + self.task_id) else: self._log.error('Task %s failed', self.task_id) await self.register_task_update(task_status='failed') @@ -437,6 +438,29 @@ class FlamencoWorker: self._push_log_to_manager = asyncio.ensure_future( self.push_to_manager(delay=self.push_log_max_interval)) + def output_produced(self, *paths: typing.Union[str, pathlib.PurePath]): + """Registers a produced output (e.g. rendered frame) with the manager. + + This performs a HTTP POST in a background task, returning as soon as + the task is scheduled. + """ + + async def do_post(): + try: + self._log.info('Sending %i path(s) to Manager', len(paths)) + resp = await self.manager.post('/output-produced', + json={'paths': [str(p) for p in paths]}, + loop=self.loop) + if resp.status_code == 204: + self._log.info('Manager accepted our output notification for %s', paths) + else: + self._log.warning('Manager rejected our output notification: %d %s', + resp.status_code, resp.text) + except Exception: + self._log.exception('error POSTing to manager /output-produced') + + self.loop.create_task(do_post()) + def generate_secret() -> str: """Generates a 64-character secret key."""