Class: Wurk::Flow::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/wurk/flow/node.rb

Overview

One node of a flow graph: a single job, plus the edges into and out of it.

Deliberately not a payload. klass, args and options are held exactly as the caller wrote them and normalized once, at creation, by Client — a node that pre-built its own job hash would be a second definition of what a job hash is, and the two would drift.

Built in two phases, because a name may be a forward reference (decision 5 in the slice plan): Builder#job constructs the node with the raw depends_on refs it was given, and #link! replaces them with resolved nodes once the whole block has run. Nothing outside the builder sees a node between the two — Wurk::Flow only ever receives frozen, linked ones.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(index:, klass:, args:, options:, declared:, name: nil, pipe: nil) ⇒ Node

Returns a new instance of Node.



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/wurk/flow/node.rb', line 55

def initialize(index:, klass:, args:, options:, declared:, name: nil, pipe: nil)
  @index        = index
  @name         = name
  @klass        = klass
  @args         = args.freeze
  @options      = options.freeze
  @declared     = declared.freeze
  @pipe         = pipe
  @feeds_pipe   = false
  @dependencies = []
  @dependents   = []
  @level        = 0
end

Instance Attribute Details

#argsArray (readonly)

Returns positional perform_async arguments, as written.

Returns:

  • (Array)

    positional perform_async arguments, as written.



29
30
31
# File 'lib/wurk/flow/node.rb', line 29

def args
  @args
end

#declaredArray (readonly)

Returns the raw depends_on: refs — nodes, names, or both.

Returns:

  • (Array)

    the raw depends_on: refs — nodes, names, or both.



37
38
39
# File 'lib/wurk/flow/node.rb', line 37

def declared
  @declared
end

#dependenciesArray<Node> (readonly)

Returns resolved dependencies. This node runs after all of them succeed.

Returns:

  • (Array<Node>)

    resolved dependencies. This node runs after all of them succeed.



46
47
48
# File 'lib/wurk/flow/node.rb', line 46

def dependencies
  @dependencies
end

#dependentsArray<Node> (readonly)

Returns the nodes that depend on this one.

Returns:

  • (Array<Node>)

    the nodes that depend on this one.



49
50
51
# File 'lib/wurk/flow/node.rb', line 49

def dependents
  @dependents
end

#indexInteger (readonly)

Returns declaration order, 0-based. The node's identity when it has no name: stable, and what creation orders writes by.

Returns:

  • (Integer)

    declaration order, 0-based. The node's identity when it has no name: stable, and what creation orders writes by.



20
21
22
# File 'lib/wurk/flow/node.rb', line 20

def index
  @index
end

#klassClass, String (readonly)

Returns the job class, as written.

Returns:

  • (Class, String)

    the job class, as written.



26
27
28
# File 'lib/wurk/flow/node.rb', line 26

def klass
  @klass
end

#levelInteger (readonly)

Returns longest path from any root, 0-based. Assigned in topological order, so a node's level is final by the time it is read.

Returns:

  • (Integer)

    longest path from any root, 0-based. Assigned in topological order, so a node's level is final by the time it is read.



53
54
55
# File 'lib/wurk/flow/node.rb', line 53

def level
  @level
end

#nameSymbol? (readonly)

Returns the name depends_on: can address this node by.

Returns:

  • (Symbol, nil)

    the name depends_on: can address this node by.



23
24
25
# File 'lib/wurk/flow/node.rb', line 23

def name
  @name
end

#optionsHash (readonly)

Returns job options merged into the payload at creation (queue:, retry:, track:, …). Not validated here: Client owns what a valid option is, and duplicating that check would fork it.

Returns:

  • (Hash)

    job options merged into the payload at creation (queue:, retry:, track:, …). Not validated here: Client owns what a valid option is, and duplicating that check would fork it.



34
35
36
# File 'lib/wurk/flow/node.rb', line 34

def options
  @options
end

#pipeNode, ... (readonly)

Returns the raw pipe: ref: the one dependency whose stored result is handed to this node as its last argument. nil for every ordinary node.

Returns:

  • (Node, Symbol, String, nil)

    the raw pipe: ref: the one dependency whose stored result is handed to this node as its last argument. nil for every ordinary node.



42
43
44
# File 'lib/wurk/flow/node.rb', line 42

def pipe
  @pipe
end

Instance Method Details

#feeds_pipe!Object

Builder-only, between #link! and #seal!.



87
88
89
90
# File 'lib/wurk/flow/node.rb', line 87

def feeds_pipe!
  @feeds_pipe = true
  self
end

#feeds_pipe?Boolean

Returns true when some dependent pipes this node's result, so creation has to enqueue it with track: true — a node whose result nothing reads is not tracked, and tracking is opt-in per job.

Returns:

  • (Boolean)

    true when some dependent pipes this node's result, so creation has to enqueue it with track: true — a node whose result nothing reads is not tracked, and tracking is opt-in per job.



84
# File 'lib/wurk/flow/node.rb', line 84

def feeds_pipe? = @feeds_pipe

#labelObject Also known as: to_s

Every error message in the builder ends up here, so it has to identify a node in a thousand-node graph unambiguously: the class says what it is, the name or index says which one.



95
# File 'lib/wurk/flow/node.rb', line 95

def label = "#{@klass}[#{@name ? @name.inspect : "##{@index}"}]"

#level!(value) ⇒ Object



108
109
110
111
# File 'lib/wurk/flow/node.rb', line 108

def level!(value)
  @level = value
  self
end

#link!(nodes) ⇒ Object

Phase two of construction: adopt the resolved dependencies and register this node as their dependent, so the graph is walkable in both directions. Builder-only — a node linked twice would double its edges.



102
103
104
105
106
# File 'lib/wurk/flow/node.rb', line 102

def link!(nodes)
  @dependencies.concat(nodes)
  nodes.each { |node| node.dependents << self }
  self
end

#piped?Boolean

Returns true when this node is handed its dependency's stored result as its last argument.

Returns:

  • (Boolean)

    true when this node is handed its dependency's stored result as its last argument.



73
# File 'lib/wurk/flow/node.rb', line 73

def piped? = !@pipe.nil?

#root?Boolean

Returns:

  • (Boolean)


69
# File 'lib/wurk/flow/node.rb', line 69

def root? = @dependencies.empty?

#seal!Object

Shallow on purpose. The edge arrays and the node are sealed because the graph is validated and must not change afterwards; args and options are frozen at construction but their contents are the caller's, and deep-freezing someone's argument objects is a side effect on their data.



117
118
119
120
121
# File 'lib/wurk/flow/node.rb', line 117

def seal!
  @dependencies.freeze
  @dependents.freeze
  freeze
end

#sourceNode?

Returns the dependency a piped node's argument comes from. The only dependency: Builder refuses pipe: on a node with more than one, because the graph is what makes "the upstream result" a single well-defined value (decision 2 in the slice plan).

Returns:

  • (Node, nil)

    the dependency a piped node's argument comes from. The only dependency: Builder refuses pipe: on a node with more than one, because the graph is what makes "the upstream result" a single well-defined value (decision 2 in the slice plan).



79
# File 'lib/wurk/flow/node.rb', line 79

def source = @dependencies.first