-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Restructure of Docker command execution and large build refactor #1524
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
Conversation
8a4751a
to
75dd2df
Compare
@@ -20,4 +20,6 @@ def handle(self, *args, **options): | |||
project_data = api.project(slug).get() | |||
p = tasks.make_api_project(project_data) | |||
log.info("Building %s" % p) | |||
tasks.update_docs(pk=p.pk, docker=True) | |||
# TODO just move this to update_api.py |
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.
Do we still need this file?
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.
We should decide what management commands are worth sticking around. Either way, build vs docker build should just be a parameter to the build comand.
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.
Agreed. We should figure out what makes sense to keep around, and document the useful ones.
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.
Also, maybe we consider implementing them as admin functions instead. Cases like build docs for a version from the admin are more useful for rtd.com, but allowing non ops folks to trigger some of the management functionality from the admin might be a win
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.
Yea, they should all be super light wrappers around util methods, so we could expose them both places.
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.
Made #1526 for this.
Outstanding issues that I am finishing up on:
|
if len(args): | ||
for slug in args: | ||
project_data = api.project(slug).get() | ||
p = tasks.make_api_project(project_data) | ||
log.info("Building %s" % p) | ||
tasks.update_docs(pk=p.pk) | ||
update_docs = tasks.UpdateDocsTask() |
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 there a reason we don't just put this in the tasks.py so it's importable like previously?
These objects will allow for multiple command execution patterns without changing the actual commands we're executing. This allows us to use Docker as a thin wrapper around container execution, instead of treating the Docker containers as a black box. This works towards per-command tracking of commands as well, giving us a far better UI around build state.
Fixes and adds more testing on build tests, including tests for pdf build failure states.
This cleans up some testing of environments and adds tests to handle extended character return gracefully.
This allows for delving into the passing behavior of a build, but the meat and potatoes is the error output.
This catches errors that did not emanate from a command
This addresses exiting due to timeout and memory usage
This will remove stale containers and throw an exception that would back out of the buildenv/task if there is a collision
Missing build data, and subsequent mocked out update_build method on envs caused a done state to not be detected, and thus success (with done state implied) was false.
Okay, to wrap this up, I've added some documentation and cleaned up the last remaining issues that I had with the code. I've push up a new repo with the docker file required to start with this build env: https://github.com/rtfd/readthedocs-docker-images It would be worth throwing some more projects at this system for integration testing. I've been through many iterations of testing on this all, but would be good to revisit initial setup issues/etc. I will follow this up with another PR that makes the UX on output not suck. It currently is a first pass and is quite noisey. |
================== | ||
|
||
Read the Docs uses container virtualization to encapsulate documentation build | ||
processes. Each build spins up a new virtual machinge using our base image, |
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.
type: "machinge" -> "machine"
|
Restructure of Docker command execution and large build refactor
Note: this is ongoing, review for design decisions for now
I was not happy with the pattern used to execute commands in containers. The original flow for executing tasks in Docker was:
This was deficient is several ways:
So, this aimed to tackle that and turned into a larger refactor, as we could be more intelligent about how we were executing commands. My first inclination was to use proper IPC to make this less fragile, but @ericholscher brought up the point that we would treat the container as a dumb container as well. The goals of this PR will be:
Environment
objects, so all forked commands are tracked.LocalEnvironment
provides local command executionshell=True
command executionresults
object in task --Environment
object tracks whether a command failed and has state on output/etcexec
mechanism instead of a single commanddocker-py
Side effects of this refactor so far include:
update_docs
is now a subclassedTask
object, allowing us to track state for the task. This could also be a separate class, but seemed more applicable as a fullTask
object with build/version/project state.Finally, some of the design decisions here:
Environments
(LocalEnvironment
/DockerEnvironment
) are used to track build state, instead of passing around results and other states through method calls on project buildCommands
no longer require running in awith
contextEnvironments
create these command objects, tracking and executing themEnvironment
wrap all calls with exception handling. If an unhandled exception bubbles up to the Environment it is reported.BuildEnvironmentError
. This will add error state to the command on the build pageThoughts on where to take this next, and I think this work sets us up for an easy transition: