Fix DockerOperator xcom - #9165
Conversation
|
@retornam @CodingJonas @CaptainCuddleCube @nalepae @akki Can I ask for review? This change looks valuable, but requires expert knowledge about the Docker/Docker API. |
|
@nullhack Can you add an example of how to use DockerOperator and XCOM? |
|
@mik-laj Thank you for the suggestions. I wrote some example on the issue Itself (#9164) if you need It to test now. I'll write the example as you asked. But I would prefer to do It after some agreement is reached if the current code is acceptable or needs changes to avoid modifying the example every time a change is required. About the Apart from that, there's one check that were not successful. I tried to read It, but don't seems related to my development (at least directly). Can you (or any other member reading It) confirm if It? |
In kubernetes, you must create a file and this file will be saved to xcom. In this way, the logs can still contain useful information for the developer.
Quarantine tests are in quarantine because they are flaky. Please ignore it. We want to fix them soon. |
|
@nullhack In cases like this (where you are opening a PR) creating the issue before hand is entierly optional -- you can just open a PR and describe the bug in the PR message; no issue needed. |
Noted. I didn't know about that, Thanks! |
Yes, the current DockerOperator is different. It reads logs from
Yes, I like this approach. One problem I see is that |
There was a problem hiding this comment.
I think the self.cli.attach method with stream=True returns a generator which allows you to read the logs in a "streaming" fashion without using significant memory.
There was a problem hiding this comment.
So I decided to just keep as a list to make the code less complex. And do not repeat the request as the original code.
I do read this in the description. I am guessing the original code makes the repeated request because of the tiny memory footprint of this API.
There was a problem hiding this comment.
So this will load the full logs of the application into memory, right? So if the application log file is 1 GB in size Airflow will start using 1GB extra RAM?
There was a problem hiding this comment.
Please correct me if I am wrong but If we .wait() here, I understand that Airflow won't show up the application logs until the Docker container stops?
For long-running applications (which typically run for 1 or more hours), I think it is very crucial to see their logs in near-real-time but with this, I think we won't see any logs until the container process completes? Sorry if I am missing something here.
There was a problem hiding this comment.
I have a couple of questions here:
- Why does Airflow explicitly need to stop the Docker container?
- If I understand correctly the
.wait()API (which we are already calling above) ensures that the container is stopped by blocking until the container gets stopped so why would the container be running at this point of time (hence why the need for this call?).
If there is some reason that justifies this call, I would suggest adding some (warn?) logging here telling the user that the container was forcefully stopped by Airflow, so that it is easy for them to debug.
|
@nullhack Could you do rebase instead of merging changes next time? This allows us to see all your changes in the "Commits" tab. It makes reviews easier. |
|
Thank you @mik-laj I was trying to find a solution for this. Will use the reflog |
ae5c769 to
b46de89
Compare
Solves the issue #9164
File changed:
airflow/providers/docker/operators/docker.pyProblems
xcom_push=Trueis enabled (andxcom_push_all=False), the output sometimes is null OR captured in wrongly.xcom_push_all=Truea bytes string (b'...') is stored as xcom, It's harder to use the output on following operators and do not conform with other operators.Stderrandstdoutare written to the same output xcom. In practice, we don't want warnings and errors messing up with the code to be parsed on following operators (But we need to capture the output on airflow logs). Sendingstderrto xcom can lead to undefined/non-deterministic behavior.Solutions:
waitbeforeattachusingstream=Truethat freezes and don't return any output (I did not dig deep, but probably will become an issue ondocker python SDKlater). A simple solution is to runlogsas It's a wrapper for attach. I followed this way and refactored part of the code, instead of two calls I saved the output on a list afterwait:Why a list, not a generator?
Because I might use two times, a generator can be used only once per request:
So I decided to just keep as a list to make the code less complex. And do not repeat the request as the original code.
This will ensure that every line will be decoded if possible, if not, then return the string representation of It (DockerOperator always return bytes string, but if in the future other objects are possible, this keep It consistent against errors).
I expect that this part can cause some discussion, because I'm changing the output from
bytestostring(my personal opinion is that beingbytesis an issue and should be changed tostringas BashOperator). There's no documentation about what should be the value stored as xcom from DockerOperator, but If this is a big issue I suggest creating a flag (xcom_string=False), but personally I don't like this approach.stderr:In the end, only logs are send to xcom and if any error is raised, the DAG run fail:
Sample Output
Issue 1:
We would expect only the last line '9'Issue 2:
Conform with similar operators

Easier to pull outputs and use on other operators

Issue 3:
Stderrdo not mess up with the outputNote that new lines are not shown on UI, but if used on some operator the output will be correctunnecessaryunnecessary