# frozen_string_literal: true require_relative "litescheduler/version" require "singleton" class Litescheduler include Singleton attr_reader :environment, :scheduler, :max_contexts, :storage, :context, :mutex def initialize @environment = detect_environment @scheduler = detect_scheduler @max_contexts = detect_max_contexts @storage = detect_storage @context = detect_context # a single mutex per process (is that ok?) @mutex = Thread::Mutex.new end # spawn a new execution context def spawn(&block) case @scheduler when :fiber then Fiber.schedule(&block) when :polyphony then spin(&block) when :iodine then Thread.new(&block) when :threaded then Thread.new(&block) else raise StandardError.new("Unknown scheduler: `#{@scheduler}`") end end # switch the execution context to allow others to run def switch if @scheduler == :fiber Fiber.scheduler.yield true elsif @scheduler == :polyphony Fiber.current.schedule Thread.current.switch_fiber true else # Thread.pass false end end # bold assumption, we will only synchronize threaded code # this is a no-op for fibers def synchronize(&block) # do nothing, just run the block as is return yield if @scheduler == :fiber return yield if @scheduler == :polyphony @mutex.synchronize(&block) end private # Detect the Rack or Rails environment. def detect_environment return Rails.env if defined? Rails return ENV["RACK_ENV"] if ENV.key?("RACK_ENV") return ENV["APP_ENV"] if ENV.key?("APP_ENV") "development" end # identify which scheduler we are running in # we currently support :fiber, :polyphony, :iodine & :threaded # in the future we might want to expand to other schedulers def detect_scheduler return :fiber if Fiber.scheduler return :polyphony if defined? Polyphony return :iodine if defined? Iodine :threaded end def detect_max_contexts return 50 if scheduler == :fiber return 50 if scheduler == :polyphony 5 end def detect_storage if scheduler == :fiber || scheduler == :poylphony Fiber.current.storage else Thread.current end end def detect_context if scheduler == :fiber || scheduler == :poylphony Fiber.current else Thread.current end end end