-
Notifications
You must be signed in to change notification settings - Fork 402
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
[RayJob] Enable job log streaming by setting PYTHONUNBUFFERED
in job container
#1375
[RayJob] Enable job log streaming by setting PYTHONUNBUFFERED
in job container
#1375
Conversation
Signed-off-by: Archit Kulkarni <[email protected]>
Signed-off-by: Archit Kulkarni <[email protected]>
Signed-off-by: Archit Kulkarni <[email protected]>
Signed-off-by: Archit Kulkarni <[email protected]>
This reverts commit a35a0d5.
This reverts commit 89f6d62.
Signed-off-by: Archit Kulkarni <[email protected]>
This reverts commit 4ebe88e.
@@ -375,6 +376,26 @@ func (r *RayJobReconciler) getSubmitterTemplate(rayJobInstance *rayv1alpha1.RayJ | |||
r.Log.Info("User-provided command is used", "command", submitterTemplate.Spec.Containers[0].Command) | |||
} | |||
|
|||
// Set PYTHONUNBUFFERED=1 for real-time logging, unless user already set it. |
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 can reuse envVarExists
.
func envVarExists(envName string, envVars []v1.EnvVar) bool { |
assert.NoError(t, err) | ||
pythonUnbufferedSet := false | ||
for _, envVar := range submitterTemplate.Spec.Containers[0].Env { | ||
if envVar.Name == "PYTHONUNBUFFERED" { |
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.
Use PythonUnbufferedEnvVarName
instead?
userValue := "0" | ||
rayJobInstanceWithTemplate.Spec.SubmitterPodTemplate.Spec.Containers[0].Env = []corev1.EnvVar{ | ||
{ | ||
Name: "PYTHONUNBUFFERED", |
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.
Use PythonUnbufferedEnvVarName
instead?
submitterTemplate, err = r.getSubmitterTemplate(rayJobInstanceWithTemplate) | ||
assert.NoError(t, err) | ||
for _, envVar := range submitterTemplate.Spec.Containers[0].Env { | ||
if envVar.Name == "PYTHONUNBUFFERED" { |
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.
Use PythonUnbufferedEnvVarName
instead?
submitterTemplate, err = r.getSubmitterTemplate(rayJobInstanceWithTemplate) | ||
assert.NoError(t, err) | ||
for _, envVar := range submitterTemplate.Spec.Containers[0].Env { | ||
if envVar.Name == "PYTHONUNBUFFERED" { |
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.
It is possible for the test to pass without entering this if
statement.
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.
Good catch!
Signed-off-by: Archit Kulkarni <[email protected]>
@kevin85421 Comments have been addressed, please take another look! |
// Set PYTHONUNBUFFERED=1 for real-time logging, unless user already set it. | ||
userProvidedValue := "" | ||
if common.EnvVarExists(PythonUnbufferedEnvVarName, submitterTemplate.Spec.Containers[0].Env) { | ||
for _, envVar := range submitterTemplate.Spec.Containers[0].Env { |
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.
It is a bit weird to iterate through the loop again after calling EnvVarExists
.
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 may consider returning bool, EnvVar
.
if common.EnvVarExists(PythonUnbufferedEnvVarName, submitterTemplate.Spec.Containers[0].Env) { | ||
for _, envVar := range submitterTemplate.Spec.Containers[0].Env { | ||
if envVar.Name == PythonUnbufferedEnvVarName { | ||
userProvidedValue = envVar.Value |
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.
The logic doesn't seem entirely correct to me, especially in cases where users can use ValueFrom
instead of Value
.
Signed-off-by: Archit Kulkarni <[email protected]>
@kevin85421 updated the PR to not check if the env var was already set, as discussed offline, because we don't anticipate any use case for |
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.
Maybe we can use submitterTemplate.Spec.Containers[common.RayContainerIndex]
to replace submitterTemplate.Spec.Containers[0]
. You can either update it in the PR or open an issue as a good first issue.
@@ -375,6 +376,12 @@ func (r *RayJobReconciler) getSubmitterTemplate(rayJobInstance *rayv1alpha1.RayJ | |||
r.Log.Info("User-provided command is used", "command", submitterTemplate.Spec.Containers[0].Command) | |||
} | |||
|
|||
// Set PYTHONUNBUFFERED=1 for real-time logging | |||
submitterTemplate.Spec.Containers[0].Env = append(submitterTemplate.Spec.Containers[0].Env, v1.EnvVar{ |
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.
Nit: What will happen if users specify PYTHONUNBUFFERED
on their own? I am not sure whether defining the same env variable twice in a container will throw an error message or override the first value.
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.
It seems the second definition will override the first one: https://www.baeldung.com/linux/kubernetes-pod-environment-variables
…fix-job-log-streaming
Signed-off-by: Archit Kulkarni <[email protected]>
Signed-off-by: Archit Kulkarni <[email protected]>
Open a good first issue #1397. |
…b container (ray-project#1375) Enable job log streaming by setting `PYTHONUNBUFFERED` in job container
…b container (ray-project#1375) Enable job log streaming by setting `PYTHONUNBUFFERED` in job container
Why are these changes needed?
Previously,
kubectl get logs job/my-rayjob
andkubectl logs my-rayjob-xxxxx
(getting the logs from the pod directly) would be empty until the job finished.This PR sets
PYTHONUNBUFFERED
in the job container so that the logs can be viewed while the job is still running.This improves the log viewing experience to match that of ordinary Kubernetes Jobs.
This PR adds unit tests, but adding an end-to-end test (e.g. submit a job that prints a log and then sleeps forever, and check that we can read the log) will require some followup work. The main issue is the following:
SUCCEEDED
) before running any Rules. But for this test, we just want the job to start before running the Rule.Related issue number
Closes #1374
Checks