-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Write build artifacts to (cloud) storage from build servers #5549
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
eadb834
9c1eae0
535f315
b61ae5d
7f2d14f
8916499
ceb7de2
9a84b07
83165b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -564,24 +564,33 @@ def run_build(self, docker, record): | |
# TODO the build object should have an idea of these states, | ||
# extend the model to include an idea of these outcomes | ||
outcomes = self.build_docs() | ||
build_id = self.build.get('id') | ||
except vcs_support_utils.LockTimeout as e: | ||
self.task.retry(exc=e, throw=False) | ||
raise VersionLockedError | ||
except SoftTimeLimitExceeded: | ||
raise BuildTimeoutError | ||
|
||
# Finalize build and update web servers | ||
if build_id: | ||
self.update_app_instances( | ||
html=bool(outcomes['html']), | ||
search=bool(outcomes['search']), | ||
localmedia=bool(outcomes['localmedia']), | ||
pdf=bool(outcomes['pdf']), | ||
epub=bool(outcomes['epub']), | ||
) | ||
else: | ||
log.warning('No build ID, not syncing files') | ||
build_id = self.build.get('id') | ||
if build_id: | ||
# Store build artifacts to storage (local or cloud storage) | ||
self.store_build_artifacts( | ||
html=bool(outcomes['html']), | ||
search=bool(outcomes['search']), | ||
localmedia=bool(outcomes['localmedia']), | ||
pdf=bool(outcomes['pdf']), | ||
epub=bool(outcomes['epub']), | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We likely need to try/except this, so that if it fails, we still run the old syncers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's fair, but I think I'll handle this try/except block in the function around the actual storage writes which could throw errors. |
||
|
||
# Finalize build and update web servers | ||
self.update_app_instances( | ||
html=bool(outcomes['html']), | ||
search=bool(outcomes['search']), | ||
localmedia=bool(outcomes['localmedia']), | ||
pdf=bool(outcomes['pdf']), | ||
epub=bool(outcomes['epub']), | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, this should probably be a try/except as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method which only had code removed shouldn't really throw an exception randomly. Do you really think we need a try block for it? |
||
else: | ||
log.warning('No build ID, not syncing files') | ||
|
||
if self.build_env.failed: | ||
self.send_notifications() | ||
|
@@ -715,6 +724,39 @@ def save_build_config(self): | |
}) | ||
self.build['config'] = config | ||
|
||
def store_build_artifacts( | ||
self, | ||
html=False, | ||
localmedia=False, | ||
search=False, | ||
pdf=False, | ||
epub=False, | ||
): | ||
""" | ||
Save build artifacts to "storage" using Django's storage API | ||
|
||
The storage could be local filesystem storage OR cloud blob storage | ||
such as S3, Azure storage or Google Cloud Storage. | ||
|
||
Remove build artifacts of types not included in this build. | ||
|
||
:param html: whether to save HTML output | ||
:param localmedia: whether to save localmedia (htmlzip) output | ||
:param search: whether to save search artifacts | ||
:param pdf: whether to save PDF output | ||
:param epub: whether to save ePub output | ||
:return: | ||
""" | ||
if getattr(settings, 'WRITE_BUILD_MEDIA', False): | ||
log.info( | ||
LOG_TEMPLATE.format( | ||
project=self.version.project.slug, | ||
version=self.version.slug, | ||
msg='Write build artifacts to media storage', | ||
), | ||
) | ||
# TODO: This will be where we actually implement this | ||
|
||
def update_app_instances( | ||
self, | ||
html=False, | ||
|
@@ -745,25 +787,6 @@ def update_app_instances( | |
|
||
delete_unsynced_media = True | ||
|
||
if getattr(storage, 'write_build_media', False): | ||
# Handle the case where we want to upload some built assets to our storage | ||
move_files.delay( | ||
self.version.pk, | ||
hostname, | ||
self.config.doctype, | ||
html=False, | ||
search=False, | ||
localmedia=localmedia, | ||
pdf=pdf, | ||
epub=epub, | ||
delete_unsynced_media=delete_unsynced_media, | ||
) | ||
# Set variables so they don't get synced in the next broadcast step | ||
localmedia = False | ||
pdf = False | ||
epub = False | ||
delete_unsynced_media = False | ||
|
||
# Broadcast finalization steps to web application instances | ||
broadcast( | ||
type='app', | ||
|
@@ -1017,16 +1040,6 @@ def move_files( | |
), | ||
]) | ||
|
||
if getattr(storage, 'write_build_media', False): | ||
# Remove the media from remote storage if it exists | ||
storage_path = version.project.get_storage_path( | ||
type_=media_type, | ||
version_slug=version.slug, | ||
) | ||
if storage.exists(storage_path): | ||
log.info('Removing %s from media storage', storage_path) | ||
storage.delete(storage_path) | ||
|
||
log.debug( | ||
LOG_TEMPLATE.format( | ||
project=version.project.slug, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this
else
on thetry
instead of theif
now? I can never remember whattry/else
does.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's correct. An
else
on atry
is taken if there is no exception. I refactored that slightly because we definedbuild_id
in atry
block and then use it later. The only reason it wasn't ever aNameError
is that we reraise the error in bothexcept
blocks.