mirror of
https://github.com/discourse/discourse.git
synced 2025-05-28 22:17:45 +08:00
DEV: Make Ruby services thread-safe
A previous refactor of the `Service::Base::Step` class introduced a non thread-safe behavior. `#call` mutates instance variables at runtime, and since a step instance is the same for any given service class, this can sometimes lead to `context` being the wrong one for the running service. This patch makes use of `Concurrent::ThreadLocalVar` to fix the issue.
This commit is contained in:

committed by
Loïc Guitaut

parent
87f8845940
commit
a4d34d60e3
@ -129,16 +129,16 @@ module Service
|
||||
|
||||
# @!visibility private
|
||||
class Step
|
||||
attr_reader :name, :method_name, :class_name, :instance, :context
|
||||
attr_reader :name, :method_name, :class_name
|
||||
|
||||
def initialize(name, method_name = name, class_name: nil)
|
||||
@name = name
|
||||
@method_name = method_name
|
||||
@class_name = class_name
|
||||
@name, @method_name, @class_name = name, method_name, class_name
|
||||
@instance = Concurrent::ThreadLocalVar.new
|
||||
@context = Concurrent::ThreadLocalVar.new
|
||||
end
|
||||
|
||||
def call(instance, context)
|
||||
@instance, @context = instance, context
|
||||
@instance.value, @context.value = instance, context
|
||||
context[result_key] = Context.build
|
||||
with_runtime { run_step }
|
||||
end
|
||||
@ -147,6 +147,10 @@ module Service
|
||||
"result.#{type}.#{name}"
|
||||
end
|
||||
|
||||
def instance = @instance.value
|
||||
|
||||
def context = @context.value
|
||||
|
||||
private
|
||||
|
||||
def run_step
|
||||
@ -252,6 +256,7 @@ module Service
|
||||
attr_reader :steps
|
||||
|
||||
def initialize(&block)
|
||||
super("")
|
||||
@steps = []
|
||||
instance_exec(&block)
|
||||
end
|
||||
@ -268,8 +273,8 @@ module Service
|
||||
attr_reader :steps, :keys
|
||||
|
||||
def initialize(*keys, &block)
|
||||
super(keys.join(":"))
|
||||
@keys = keys
|
||||
@name = keys.join(":")
|
||||
@steps = []
|
||||
instance_exec(&block)
|
||||
end
|
||||
@ -308,7 +313,7 @@ module Service
|
||||
attr_reader :steps, :exceptions
|
||||
|
||||
def initialize(exceptions, &block)
|
||||
@name = "default"
|
||||
super("default")
|
||||
@steps = []
|
||||
@exceptions = exceptions.presence || [StandardError]
|
||||
instance_exec(&block)
|
||||
|
Reference in New Issue
Block a user