Module: Restate::ServiceDSL

Included in:
Service, VirtualObject, Workflow
Defined in:
lib/restate/service_dsl.rb

Overview

Shared class-level DSL for defining Restate services via class inheritance.

Extended into Service, VirtualObject, and Workflow. Provides the handler, shared, main, and service_name class macros.

Examples:

class Counter < Restate::VirtualObject
  handler def add(ctx, addend)
    old = ctx.get('counter') || 0
    ctx.set('counter', old + addend)
    old + addend
  end
end

Instance Method Summary collapse

Instance Method Details

#abort_timeout(seconds) ⇒ Object

Set the abort timeout (in seconds) for this service.

Parameters:

  • seconds (Numeric)

    timeout in seconds



154
155
156
# File 'lib/restate/service_dsl.rb', line 154

def abort_timeout(seconds)
  @_abort_timeout = seconds
end

#description(text = nil) ⇒ String?

Set or get a human-readable description for this service.

Parameters:

  • text (String, nil) (defaults to: nil)

    when provided, sets the description

Returns:

  • (String, nil)

    the current description



124
125
126
127
128
129
130
# File 'lib/restate/service_dsl.rb', line 124

def description(text = nil)
  if text
    @_description = text
  else
    @_description
  end
end

#enable_lazy_state(value = true) ⇒ Object

Enable lazy state loading for all handlers in this service. When enabled, state is fetched on demand rather than pre-loaded.

Parameters:

  • value (Boolean) (defaults to: true)

    whether to enable lazy state



116
117
118
# File 'lib/restate/service_dsl.rb', line 116

def enable_lazy_state(value = true) # rubocop:disable Style/OptionalBooleanParameter
  @_enable_lazy_state = value
end

#handlersHash{String => Handler}

Returns a hash of handler name (String) to Handler. Built lazily on first access and cached.

Returns:



245
246
247
# File 'lib/restate/service_dsl.rb', line 245

def handlers
  @_handlers ||= _build_handlers # rubocop:disable Naming/MemoizedInstanceVariableName
end

#idempotency_retention(seconds) ⇒ Object

Set the idempotency retention (in seconds) for this service.

Parameters:

  • seconds (Numeric)

    retention in seconds



168
169
170
# File 'lib/restate/service_dsl.rb', line 168

def idempotency_retention(seconds)
  @_idempotency_retention = seconds
end

#inactivity_timeout(seconds) ⇒ Object

Set the inactivity timeout (in seconds) for this service.

Parameters:

  • seconds (Numeric)

    timeout in seconds



147
148
149
# File 'lib/restate/service_dsl.rb', line 147

def inactivity_timeout(seconds)
  @_inactivity_timeout = seconds
end

#ingress_private(value = true) ⇒ Object

Mark this service as private to the ingress.

Parameters:

  • value (Boolean) (defaults to: true)

    whether the service is ingress-private



175
176
177
# File 'lib/restate/service_dsl.rb', line 175

def ingress_private(value = true) # rubocop:disable Style/OptionalBooleanParameter
  @_ingress_private = value
end

#inherited(subclass) ⇒ Object

Called when a subclass is created; initializes the handler registry.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/restate/service_dsl.rb', line 20

def inherited(subclass) # rubocop:disable Metrics/MethodLength
  super
  subclass.instance_variable_set(:@_handler_registry, {})
  subclass.instance_variable_set(:@_service_name, nil)
  subclass.instance_variable_set(:@_handlers, nil)
  subclass.instance_variable_set(:@_enable_lazy_state, nil)
  subclass.instance_variable_set(:@_description, nil)
  subclass.instance_variable_set(:@_metadata, nil)
  subclass.instance_variable_set(:@_inactivity_timeout, nil)
  subclass.instance_variable_set(:@_abort_timeout, nil)
  subclass.instance_variable_set(:@_journal_retention, nil)
  subclass.instance_variable_set(:@_idempotency_retention, nil)
  subclass.instance_variable_set(:@_ingress_private, nil)
  subclass.instance_variable_set(:@_invocation_retry_policy, nil)
  subclass.instance_variable_set(:@_state_declarations, {})
end

#invocation_retry_policy(initial_interval: nil, max_interval: nil, max_attempts: nil, exponentiation_factor: nil, on_max_attempts: nil) ⇒ Object

Set the invocation retry policy for this service.

Parameters:

  • initial_interval (Numeric, nil) (defaults to: nil)

    initial retry interval in seconds

  • max_interval (Numeric, nil) (defaults to: nil)

    maximum retry interval in seconds

  • max_attempts (Integer, nil) (defaults to: nil)

    maximum number of retry attempts

  • exponentiation_factor (Numeric, nil) (defaults to: nil)

    backoff exponentiation factor

  • on_max_attempts (Symbol, String, nil) (defaults to: nil)

    action on max attempts (:pause or :kill)



186
187
188
189
190
191
192
193
194
195
# File 'lib/restate/service_dsl.rb', line 186

def invocation_retry_policy(initial_interval: nil, max_interval: nil, max_attempts: nil,
                            exponentiation_factor: nil, on_max_attempts: nil)
  @_invocation_retry_policy = {
    initial_interval: initial_interval,
    max_interval: max_interval,
    max_attempts: max_attempts,
    exponentiation_factor: exponentiation_factor,
    on_max_attempts: on_max_attempts
  }.compact
end

#journal_retention(seconds) ⇒ Object

Set the journal retention (in seconds) for this service.

Parameters:

  • seconds (Numeric)

    retention in seconds



161
162
163
# File 'lib/restate/service_dsl.rb', line 161

def journal_retention(seconds)
  @_journal_retention = seconds
end

#lazy_state?Boolean

Returns the service-level lazy state setting (nil if not set).

Returns:

  • (Boolean)


207
208
209
# File 'lib/restate/service_dsl.rb', line 207

def lazy_state?
  @_enable_lazy_state
end

#metadata(hash = nil) ⇒ Hash?

Set or get metadata for this service.

Parameters:

  • hash (Hash, nil) (defaults to: nil)

    when provided, sets the metadata

Returns:

  • (Hash, nil)

    the current metadata



136
137
138
139
140
141
142
# File 'lib/restate/service_dsl.rb', line 136

def (hash = nil)
  if hash
    @_metadata = hash
  else
    @_metadata
  end
end

#service_name(name = nil) ⇒ String

Get or set the service name. Defaults to the unqualified class name.

Parameters:

  • name (String, nil) (defaults to: nil)

    when provided, sets the service name

Returns:

  • (String)

    the current service name



104
105
106
107
108
109
110
# File 'lib/restate/service_dsl.rb', line 104

def service_name(name = nil)
  if name
    @_service_name = name
  else
    @_service_name ||= self.name&.split('::')&.last # rubocop:disable Naming/MemoizedInstanceVariableName
  end
end

#service_tagServiceTag

Returns the ServiceTag for this class-based service. Subclasses must define _service_kind.

Returns:



201
202
203
204
# File 'lib/restate/service_dsl.rb', line 201

def service_tag
  ServiceTag.new(kind: _service_kind, name: service_name,
                 description: @_description, metadata: @_metadata)
end

#state(name, default: nil, serde: nil) ⇒ Object

Declare a durable state entry with auto-generated getter, setter, and clear methods. Only available on VirtualObject and Workflow.

The generated methods delegate to the current Restate context via Thread.current (fiber-scoped in Ruby 3.0+), so they work correctly across concurrent invocations.

Examples:

class Counter < Restate::VirtualObject
  state :count, default: 0

  handler def add(ctx, addend)
    self.count += addend  # reads then writes via ctx.get/ctx.set
  end

  shared def get(ctx)
    count  # reads via ctx.get, returns 0 if unset
  end
end

Parameters:

  • name (Symbol)

    state key name

  • default (Object, nil) (defaults to: nil)

    default value returned when state is not set

  • serde (Object) (defaults to: nil)

    serializer/deserializer (defaults to JsonSerde)



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/restate/service_dsl.rb', line 59

def state(name, default: nil, serde: nil) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
  unless respond_to?(:_service_kind) && %w[object workflow].include?(_service_kind)
    Kernel.raise ArgumentError, 'state declarations are only available on VirtualObject and Workflow'
  end

  name = name.to_sym
  @_state_declarations[name] = { default: default, serde: serde }
  state_key = name.to_s
  state_serde = serde
  state_default = default

  # Getter: reads from durable state, returns default if unset
  define_method(name) do
    ctx = Thread.current[:restate_context]
    Kernel.raise 'Not inside a Restate handler' unless ctx

    val = state_serde ? ctx.get(state_key, serde: state_serde) : ctx.get(state_key)
    val.nil? ? state_default : val
  end

  # Setter: writes to durable state
  define_method(:"#{name}=") do |value|
    ctx = Thread.current[:restate_context]
    Kernel.raise 'Not inside a Restate handler' unless ctx

    if state_serde
      ctx.set(state_key, value, serde: state_serde)
    else
      ctx.set(state_key, value)
    end
  end

  # Clear: removes the state entry
  define_method(:"clear_#{name}") do
    ctx = Thread.current[:restate_context]
    Kernel.raise 'Not inside a Restate handler' unless ctx

    ctx.clear(state_key)
  end
end

#svc_abort_timeoutObject

Returns the service-level abort timeout (nil if not set).



217
218
219
# File 'lib/restate/service_dsl.rb', line 217

def svc_abort_timeout
  @_abort_timeout
end

#svc_idempotency_retentionObject

Returns the service-level idempotency retention (nil if not set).



227
228
229
# File 'lib/restate/service_dsl.rb', line 227

def svc_idempotency_retention
  @_idempotency_retention
end

#svc_inactivity_timeoutObject

Returns the service-level inactivity timeout (nil if not set).



212
213
214
# File 'lib/restate/service_dsl.rb', line 212

def svc_inactivity_timeout
  @_inactivity_timeout
end

#svc_ingress_privateObject

Returns the service-level ingress private setting (nil if not set).



232
233
234
# File 'lib/restate/service_dsl.rb', line 232

def svc_ingress_private
  @_ingress_private
end

#svc_invocation_retry_policyObject

Returns the service-level invocation retry policy (nil if not set).



237
238
239
# File 'lib/restate/service_dsl.rb', line 237

def svc_invocation_retry_policy
  @_invocation_retry_policy
end

#svc_journal_retentionObject

Returns the service-level journal retention (nil if not set).



222
223
224
# File 'lib/restate/service_dsl.rb', line 222

def svc_journal_retention
  @_journal_retention
end