diff --git a/config/metrics.rb b/config/metrics.rb new file mode 100644 index 0000000..f8ae1c2 --- /dev/null +++ b/config/metrics.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +def prepare + require "metrics/provider/async/task" +end diff --git a/config/sus.rb b/config/sus.rb index ced7124..ee98da5 100644 --- a/config/sus.rb +++ b/config/sus.rb @@ -6,4 +6,10 @@ require "covered/sus" include Covered::Sus -ENV["CONSOLE_LEVEL"] ||= "fatal" +# ENV["CONSOLE_LEVEL"] ||= "fatal" + +ENV["TRACES_BACKEND"] ||= "traces/backend/test" +require "traces" + +ENV["METRICS_BACKEND"] ||= "metrics/backend/test" +require "metrics" diff --git a/config/traces.rb b/config/traces.rb new file mode 100644 index 0000000..281c335 --- /dev/null +++ b/config/traces.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +def prepare + require "traces/provider/async/task" + require "traces/provider/async/scheduler" +end diff --git a/gems.rb b/gems.rb index 706984e..d00bf44 100644 --- a/gems.rb +++ b/gems.rb @@ -25,6 +25,9 @@ gem "decode" gem "rubocop" + gem "traces" + gem "metrics" + gem "sus-fixtures-async" gem "sus-fixtures-console", "~> 0.3" diff --git a/lib/metrics/provider/async.rb b/lib/metrics/provider/async.rb new file mode 100644 index 0000000..a4252d4 --- /dev/null +++ b/lib/metrics/provider/async.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "async/task" diff --git a/lib/metrics/provider/async/task.rb b/lib/metrics/provider/async/task.rb new file mode 100644 index 0000000..daf6f8e --- /dev/null +++ b/lib/metrics/provider/async/task.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "../../../async/task" +require "metrics/provider" + +Metrics::Provider(Async::Task) do + ASYNC_TASK_SCHEDULED = Metrics.metric("async.task.scheduled", :counter, description: "The number of tasks scheduled.") + + def schedule(&block) + ASYNC_TASK_SCHEDULED.emit(1) + + super(&block) + end +end diff --git a/lib/traces/provider/async.rb b/lib/traces/provider/async.rb new file mode 100644 index 0000000..1256551 --- /dev/null +++ b/lib/traces/provider/async.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "async/task" \ No newline at end of file diff --git a/lib/traces/provider/async/scheduler.rb b/lib/traces/provider/async/scheduler.rb new file mode 100644 index 0000000..12ad408 --- /dev/null +++ b/lib/traces/provider/async/scheduler.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "../../../async/scheduler" +require "traces/provider" + +# Traces::Provider(Async::Scheduler) do +# def yield +# Traces.trace("async.scheduler.yield") {super} +# end + +# def block(blocker, timeout) +# attributes = { +# blocker: blocker.to_s, +# timeout: timeout +# } + +# Traces.trace("async.scheduler.block", attributes: attributes) {super} +# end + +# def transfer +# Traces.trace("async.scheduler.transfer") {super} +# end + +# # @asynchronous May be non-blocking.. +# def address_resolve(hostname) +# attributes = { +# hostname: hostname +# } + +# Traces.trace("async.scheduler.address_resolve", attributes: attributes) {super} +# end + +# def process_wait(pid, flags) +# attributes = { +# pid: pid, +# flags: flags +# } + +# Traces.trace("async.scheduler.process_wait", attributes: attributes) {super} +# end + +# def with_timeout(duration, exception = Async::TimeoutError, message = "execution expired", &block) +# attributes = { +# duration: duration, +# } + +# Traces.trace("async.scheduler.with_timeout", attributes: attributes) {super} +# end +# end diff --git a/lib/traces/provider/async/task.rb b/lib/traces/provider/async/task.rb new file mode 100644 index 0000000..7cb1151 --- /dev/null +++ b/lib/traces/provider/async/task.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022, by Samuel Williams. + +require_relative "../../../async/task" +require "traces/provider" + +Traces::Provider(Async::Task) do + def schedule(&block) + unless self.transient? + trace_context = Traces.trace_context + end + + super do + Traces.trace_context = trace_context + + if annotation = self.annotation + attributes = { + "annotation" => annotation + } + end + + Traces.trace("async.task", attributes: attributes) do + yield + end + end + end +end diff --git a/test/async/barrier.rb b/test/async/barrier.rb index e07c5fe..c6f8ff9 100644 --- a/test/async/barrier.rb +++ b/test/async/barrier.rb @@ -55,9 +55,6 @@ task2 = barrier.async do end - expect(task1).to be(:failed?) - expect(task2).to be(:finished?) - expect{barrier.wait}.to raise_exception(RuntimeError, message: be =~ /Boom/) barrier.wait until barrier.empty? @@ -65,6 +62,9 @@ expect{task1.wait}.to raise_exception(RuntimeError, message: be =~ /Boom/) expect(barrier).to be(:empty?) + + expect(task1).to be(:failed?) + expect(task2).to be(:finished?) end it "waits for tasks in order" do diff --git a/test/async/reactor.rb b/test/async/reactor.rb index 70516f8..abac8f5 100644 --- a/test/async/reactor.rb +++ b/test/async/reactor.rb @@ -5,6 +5,7 @@ # Copyright, 2017, by Devin Christensen. require "async" +require "async/variable" require "sus/fixtures/async" require "benchmark/ips" @@ -229,14 +230,14 @@ start_time = Time.now subject.run do |task| - condition = Async::Condition.new + variable = Async::Variable.new task.with_timeout(duration) do task.async do - condition.wait + variable.wait end - condition.signal + variable.resolve task.yield diff --git a/test/async/task.rb b/test/async/task.rb index 1aaa615..3a3ebe9 100644 --- a/test/async/task.rb +++ b/test/async/task.rb @@ -50,18 +50,18 @@ it "can yield back to scheduler" do state = nil - reactor.async do |task| + reactor.run do |task| child = task.async do state = :yielding Async::Task.yield state = :yielded end + # Async::Task. + Fiber.scheduler.resume(child.fiber) end - reactor.run - expect(state).to be == :yielded end end @@ -750,9 +750,11 @@ def sleep_forever raise "The space time converter has failed." end - expect do - task.wait - end.to raise_exception(RuntimeError, message: be =~ /space time converter/) + reactor.run do + expect do + task.wait + end.to raise_exception(RuntimeError, message: be =~ /space time converter/) + end expect(task.result).to be_a(RuntimeError) end