WIP: 103268-job-task-progress #104185

Draft
Nitin-Rawat-1 wants to merge 19 commits from Nitin-Rawat-1/flamenco:103268-job-task-progress into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Contributor

Issue #103268: This PR aims to implement the feature in the reference issue in the future. Right now approval of the project maintainer is required for the work done till now.

Issue #103268: This PR aims to implement the feature in the reference issue in the future. Right now approval of the project maintainer is required for the work done till now.
Nitin-Rawat-1 added 6 commits 2023-02-17 13:13:36 +01:00
Add an endpoint for the Manager, to allow Workers, to send progress update of the task. Define the schema of the request body to hit this endpoint.

Issue: #103268
`SocketIOTaskProgressUpdate` objects are meant to be broadcast to SocketIO clients (i.e. the web interface). They are sent to the job specific room, just like task updates.
Blender render command is being extended in order to accept a frameRange property which is optional. FrameRange property will help in the calculation of the progress of a task.

Issue: 103268
Nitin-Rawat-1 requested review from Sybren A. Stüvel 2023-02-17 14:12:52 +01:00
Nitin-Rawat-1 added 1 commit 2023-02-21 03:54:45 +01:00
Nitin-Rawat-1 added 1 commit 2023-02-21 10:45:40 +01:00
Nitin-Rawat-1 added 1 commit 2023-02-23 10:38:03 +01:00
Nitin-Rawat-1 added 1 commit 2023-03-06 15:15:04 +01:00
Nitin-Rawat-1 added 2 commits 2023-03-06 16:43:10 +01:00
Nitin-Rawat-1 force-pushed 103268-job-task-progress from 2abfae2a0c to 218e476e78 2023-03-07 06:52:12 +01:00 Compare
Sybren A. Stüvel requested changes 2023-03-10 11:12:25 +01:00
Sybren A. Stüvel left a comment
Owner

I think this logic should be pulled into a separate function, and probably even use a different struct. That way the 'keeping track of frame processing progress' logic is separate from the 'rendering with Blender' code. I'm thinking along the lines of something like this:

package progress

// Indexed keeps track of the progress of indexed 'things'.
//
// This is typically used to keep track of the progress of rendering multiple
// frames in a single task.
type Indexed struct {
	completed map[int]bool // Map from index of the 'thing' to completion status.
	expected  int          // Number of things to complete before considering the work 'done'.
}

// NewIndexed returns a new indexed progress tracker for counting `expectedNumberOfThings` things.
func NewIndexed(expectedNumberOfThings int) Indexed {
	return Indexed{
		completed: make(map[int]bool),
		expected:  expectedNumberOfThings,
	}
}

// Completed marks the thing with the given index to be done.
// If this index was already marked 'done', this is a no-op.
func (isp *Indexed) Completed(index int) {
	isp.completed[index] = true
}

// IsDone returns true when at least the expected number of things have been marked 'completed'.
func (isp *Indexed) IsDone() bool {
	return isp.count() >= isp.expected
}

// Progress returns the progress so far, as (completed, total expected) counts.
func (isp *Indexed) Progress() (completed, totalExpected int) {
	completed = isp.count()
	totalExpected = isp.expected
	return
}

// count returns the number of indexed things that are marked 'completed'.
func (isp *Indexed) count() int {
	count := 0
	for _, value := range isp.completed {
		if value {
			count++
		}
	}
	return count
}

In theory a task can consist of multiple blender-render commands, though, so this will have to be tracked on the task level, not just the command level. It's probably a good idea to create some CommandProgressListener interface, and use that to bridge the command runner functions and the task executor.

I think this logic should be pulled into a separate function, and probably even use a different struct. That way the 'keeping track of frame processing progress' logic is separate from the 'rendering with Blender' code. I'm thinking along the lines of something like this: ```go package progress // Indexed keeps track of the progress of indexed 'things'. // // This is typically used to keep track of the progress of rendering multiple // frames in a single task. type Indexed struct { completed map[int]bool // Map from index of the 'thing' to completion status. expected int // Number of things to complete before considering the work 'done'. } // NewIndexed returns a new indexed progress tracker for counting `expectedNumberOfThings` things. func NewIndexed(expectedNumberOfThings int) Indexed { return Indexed{ completed: make(map[int]bool), expected: expectedNumberOfThings, } } // Completed marks the thing with the given index to be done. // If this index was already marked 'done', this is a no-op. func (isp *Indexed) Completed(index int) { isp.completed[index] = true } // IsDone returns true when at least the expected number of things have been marked 'completed'. func (isp *Indexed) IsDone() bool { return isp.count() >= isp.expected } // Progress returns the progress so far, as (completed, total expected) counts. func (isp *Indexed) Progress() (completed, totalExpected int) { completed = isp.count() totalExpected = isp.expected return } // count returns the number of indexed things that are marked 'completed'. func (isp *Indexed) count() int { count := 0 for _, value := range isp.completed { if value { count++ } } return count } ``` In theory a task can consist of multiple blender-render commands, though, so this will have to be tracked on the task level, not just the command level. It's probably a good idea to create some `CommandProgressListener` interface, and use that to bridge the command runner functions and the task executor.
@ -21,2 +22,4 @@
var regexpFileSaved = regexp.MustCompile("Saved: '(.*)'")
var regexpFrameNumber = regexp.MustCompile("Fra:[0-9]+")
var prevFrame string

I don't see the need to declare these variables here.

I don't see the need to declare these variables here.
@ -27,6 +32,7 @@ type BlenderParameters struct {
argsBefore []string // Additional CLI arguments defined by the job compiler script, to go before the blend file name.
blendfile string // Path of the file to open.
args []string // Additional CLI arguments defined by the job compiler script, to go after the blend file name.
numFrames float64 // Additional CLI argument defined by the job compiler script, to define the total number of frame that are needed to be rendered.

This is not a CLI argument. It's just for Flamenco's bookkeeping, and won't be passed to Blender in any way.

This is not a CLI argument. It's just for Flamenco's bookkeeping, and won't be passed to Blender in any way.
@ -47,2 +53,4 @@
wg.Add(1)
go func() {
prevFrame = ""
renderedNumFrames = 0

Why are these set here? They're not used in this goroutine. Also Go initializes variables to the zero value, so it's likely to be a no-op. It can cause a race condition, though, because the goroutine runs asynchronously from the rest of the code.

Why are these set here? They're not used in this goroutine. Also Go initializes variables to the zero value, so it's likely to be a no-op. It can cause a race condition, though, because the goroutine runs asynchronously from the rest of the code.
@ -140,1 +148,4 @@
// Ignore the `ok` return value, as a missing numFrames key is fine:
parameters.numFrames, _ = cmdParameter[float64](cmd, "numFrames")
if parameters.numFrames != 0 {

This if is not necessary. totalNumFrames is initialized to zero anyway, so if paramters.numFrames == 0, the assignment can safely be done as it just reassigns zero.

This `if` is not necessary. `totalNumFrames` is initialized to zero anyway, so if `paramters.numFrames == 0`, the assignment can safely be done as it just reassigns zero.
Sybren A. Stüvel requested changes 2023-03-10 11:15:41 +01:00
@ -50,2 +52,3 @@
//go:generate go run github.com/golang/mock/mockgen -destination mocks/cli_runner.gen.go -package mocks git.blender.org/flamenco/internal/worker CommandLineRunner
// CommandLineRunner is an interface around exec.CommandContext().
//
//go:generate go run github.com/golang/mock/mockgen -destination mocks/cli_runner.gen.go -package mocks git.blender.org/flamenco/internal/worker CommandLineRunner

Try to keep the changes in a PR to a minimum. Unless there is a good reason, keep the ordering of these comments the same. That'll make it easier to see what actually changed.

Try to keep the changes in a PR to a minimum. Unless there is a good reason, keep the ordering of these comments the same. That'll make it easier to see what actually changed.
@ -100,0 +109,4 @@
if ctx.Err() != nil {
return ctx.Err()
}
resp, err := l.client.TaskProgressUpdateWithResponse(ctx, taskID, progress)

This should not use the API client directly. If the Manager cannot be reached, the progress updates should be queued in the buffer, just like regular task updates.

This should not use the API client directly. If the Manager cannot be reached, the progress updates should be queued in the buffer, just like regular task updates.
Nitin-Rawat-1 added 1 commit 2023-04-15 10:38:51 +02:00
Nitin-Rawat-1 added 1 commit 2023-04-15 11:19:52 +02:00
Nitin-Rawat-1 added 1 commit 2023-04-17 17:36:49 +02:00
Nitin-Rawat-1 added 2 commits 2023-04-25 11:42:25 +02:00
Nitin-Rawat-1 added 1 commit 2023-05-01 14:04:37 +02:00
This pull request has changes conflicting with the target branch.
  • addon/flamenco/manager/api/worker_mgt_api.py
  • addon/flamenco/manager/docs/WorkerMgtApi.md
  • addon/flamenco/manager/models/__init__.py
  • addon/flamenco/manager_README.md
  • internal/manager/job_compilers/scripts.go
  • internal/manager/job_compilers/scripts/simple_blender_render.js
  • internal/worker/command_blender.go
  • internal/worker/command_exe.go
  • pkg/api/flamenco-openapi.yaml
  • pkg/api/openapi_client.gen.go

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 103268-job-task-progress:Nitin-Rawat-1-103268-job-task-progress
git checkout Nitin-Rawat-1-103268-job-task-progress
Sign in to join this conversation.
No description provided.