- 
                Notifications
    You must be signed in to change notification settings 
- Fork 3.8k
chore(engine): add workflow package #19511
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
          
     Merged
      
      
    
  
     Merged
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            5 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      664881b
              
                chore(engine): expose physical node in tree representation
              
              
                rfratto 5dad4f9
              
                chore(engine): allow manipulation of physical plan DAGs
              
              
                rfratto adf9423
              
                chore(engine): introduce concept of shardable nodes
              
              
                rfratto 382c2c1
              
                chore(engine): add workflow package
              
              
                rfratto 2db4323
              
                fixup! chore(engine): add workflow package
              
              
                rfratto File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| package workflow | ||
|  | ||
| import ( | ||
| "context" | ||
| "fmt" | ||
|  | ||
| "github.com/grafana/loki/v3/pkg/engine/internal/executor" | ||
| ) | ||
|  | ||
| // A Runner can asynchronously execute a workflow. | ||
| type Runner interface { | ||
| // AddStreams registers a list of Streams that can be used by Tasks. | ||
| // AddStreams returns an error if any of the streams (by ID) are already | ||
| // registered. | ||
| // | ||
| // The provided handler will be called whenever any of the provided streams | ||
| // change state. | ||
| AddStreams(ctx context.Context, handler StreamEventHandler, streams ...*Stream) error | ||
|         
                  ivkalita marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
|  | ||
| // RemoveStreams removes a list of Streams that can be used by Tasks. The | ||
| // associated [StreamEventHandler] will no longer be called for removed | ||
| // streams. | ||
| // | ||
| // RemoveStreams returns an error if there are active tasks using the | ||
| // streams. | ||
| RemoveStreams(ctx context.Context, streams ...*Stream) error | ||
|  | ||
| // Listen binds the caller as the receiver of the specified stream. | ||
| // Listening on a stream prevents tasks from reading from it. | ||
| Listen(ctx context.Context, stream *Stream) (executor.Pipeline, error) | ||
|  | ||
| // Start begins executing the provided tasks in the background. Start | ||
| // returns an error if any of the Tasks references an unregistered Stream, | ||
| // or if any of the tasks are a reader of a stream that's already bound. | ||
| // | ||
| // The provided handler will be called whenever any of the provided tasks | ||
| // change state. | ||
| // | ||
| // Implementations must track executed tasks until the tasks enter a | ||
| // terminal state. | ||
| // | ||
| // The provided context is used for the lifetime of the tasks. Cancelling | ||
| // the context will cancel all tasks, and close associated streams for | ||
| // sending. | ||
| Start(ctx context.Context, handler TaskEventHandler, tasks ...*Task) error | ||
|  | ||
| // Cancel requests cancelation of the specified tasks. Cancel returns an | ||
| // error if any of the tasks were not found. | ||
| Cancel(ctx context.Context, tasks ...*Task) error | ||
| } | ||
|  | ||
| // StreamEventHandler is a function that handles events for changed streams. | ||
| type StreamEventHandler func(ctx context.Context, s *Stream, newState StreamState) | ||
|  | ||
| // StreamState represents the state of a stream. It is sent as an event by a | ||
| // [Runner] whenever a stream associated with a task changes its state. | ||
| // | ||
| // The zero value of StreamState is an inactive stream. | ||
| type StreamState int | ||
|  | ||
| const ( | ||
| // StreamStateIdle represents a stream that is waiting for both the sender | ||
| // and receiver to be available. | ||
| StreamStateIdle StreamState = iota | ||
|  | ||
| // StreamStateOpen represents a stream that is open and transmitting data. | ||
| StreamStateOpen | ||
|  | ||
| // StreamStateBlocked represents a stream that is blocked (by backpressure) | ||
| // on sending data. | ||
| StreamStateBlocked | ||
|  | ||
| // StreamStateClosed represents a stream that is closed and no longer | ||
| // transmitting data. | ||
| StreamStateClosed | ||
| ) | ||
|  | ||
| var streamStates = [...]string{ | ||
| "Idle", | ||
| "Open", | ||
| "Blocked", | ||
| "Closed", | ||
| } | ||
|  | ||
| // String returns a string representation of the StreamState. | ||
| func (s StreamState) String() string { | ||
| if s >= 0 && int(s) < len(streamStates) { | ||
| return streamStates[s] | ||
| } | ||
| return fmt.Sprintf("StreamState(%d)", s) | ||
| } | ||
|  | ||
| // TaskEventHandler is a function that handles events for changed tasks. | ||
| type TaskEventHandler func(ctx context.Context, t *Task, newState TaskState) | ||
|  | ||
| // TaskState represents the state of a Task. It is sent as an event by a | ||
| // [Runner] whenever a Task associated with a task changes its state. | ||
| type TaskState int | ||
|  | ||
| const ( | ||
| // TaskStateCreated represents the initial state for a Task, where it has | ||
| // been created but not given to a [Runner]. | ||
| TaskStateCreated TaskState = iota | ||
|  | ||
| // TaskStatePending represents a Task that is pending execution by a | ||
| // [Runner]. | ||
| TaskStatePending | ||
|  | ||
| // TaskStateRunning represents a Task that is currently being executed by a | ||
| // [Runner]. | ||
| TaskStateRunning | ||
|  | ||
| // TaskStateCompleted represents a Task that has completed successfully. | ||
| TaskStateCompleted | ||
|  | ||
| // TaskStateCancelled represents a Task that has been cancelled, either by a | ||
| // [Runner] or the owning [Workflow]. | ||
| TaskStateCancelled | ||
|  | ||
| // TaskStateFailed represents a Task that has failed during execution. | ||
| TaskStateFailed | ||
| ) | ||
|  | ||
| var TaskStates = [...]string{ | ||
| "Created", | ||
| "Pending", | ||
| "Running", | ||
| "Completed", | ||
| "Cancelled", | ||
| "Failed", | ||
| } | ||
|  | ||
| // Terminal returns true if the TaskState is terminal. | ||
| func (s TaskState) Terminal() bool { | ||
| return s == TaskStateCompleted || s == TaskStateCancelled || s == TaskStateFailed | ||
| } | ||
|  | ||
| // String returns a string representation of the TaskState. | ||
| func (s TaskState) String() string { | ||
| if s >= 0 && int(s) < len(TaskStates) { | ||
| return TaskStates[s] | ||
| } | ||
| return fmt.Sprintf("TaskState(%d)", s) | ||
| } | ||
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package workflow | ||
|  | ||
| import ( | ||
| "github.com/oklog/ulid/v2" | ||
|  | ||
| "github.com/grafana/loki/v3/pkg/engine/internal/planner/physical" | ||
| ) | ||
|  | ||
| // A Task is a single unit of work within a workflow. Each Task is a partition | ||
| // of a local physical plan. | ||
| type Task struct { | ||
| // ULID is a unique identifier of the Task. | ||
| ULID ulid.ULID | ||
| 
      Comment on lines
    
      +12
     to 
      +13
    
   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 could be UUIDv7, but I picked ULID here because: 
 ULID also requires monotonic counters, which guarantees that a single instance of a process can't generate collisions. With UUIDv7, it's recommended but not required, so it depends on the library you use. | ||
|  | ||
| // Fragment is the local physical plan that this Task represents. | ||
| Fragment *physical.Plan | ||
|  | ||
| // Sources defines which Streams physical nodes read from. Sources are only | ||
| // defined for nodes in the Fragment which read data across task boundaries. | ||
| Sources map[physical.Node][]*Stream | ||
|  | ||
| // Sinks defines which Streams physical nodes write to. Sinks are only | ||
| // defined for nodes in the Fragment which write data across task boundaries. | ||
| Sinks map[physical.Node][]*Stream | ||
| } | ||
|  | ||
| // ID returns the string form of the Task's ULID. | ||
| func (t *Task) ID() string { return t.ULID.String() } | ||
|  | ||
| // A Stream is an abstract representation of how data flows across Task | ||
| // boundaries. Each Stream has exactly one sender (a Task), and one receiver | ||
| // (either another Task or the owning [Workflow]). | ||
| type Stream struct { | ||
| // ULID is a unique identifier of the Stream. | ||
| ULID ulid.ULID | ||
| } | ||
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
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.
This is used by
workflow.Sprintto allow workflow printing to hook into the tree produced by the physical plan and add additional context for nodes (the streams to write to or read from).