Multi-Server State-based

Events can be expressed as state transitions $\mathcal{f}(x, \gamma)$ with $x \in \mathcal{X},\ \gamma \in \Gamma(x)$ of finite automata. The following example models 8 servers as state machines serving a queue of jobs:

using DiscreteEvents, Printf, Random, Distributions

const p = 0.3

abstract type ๐‘‹ end    # define states
struct Idle <: ๐‘‹ end
struct Busy <: ๐‘‹ end

abstract type ๐ธ end    # events
struct Load <: ๐ธ end
struct Release <: ๐ธ end
struct Setup <: ๐ธ end

mutable struct Server  # state machine body
    id::Int
    c::Clock
    state::๐‘‹
    job::Int
end

ex = Exponential()
queue = Vector{Int}()
done  = Vector{Int}()
Base.isready(x::Array) = !isempty(x)

# transition functions
function ๐’‡!(A::Server, ::Idle, ::Load)
    A.job = pop!(queue)
    A.state = Busy()
    @printf("%5.2f: server %d took job %d\n", tau(A.c), A.id, A.job)
    event!(A.c, fun(๐’‡!, A, A.state, Release()), after, rand(ex))
end

function ๐’‡!(A::Server, ::Busy, ::Release)
    if rand() > p
        push!(queue, A.job)
    else
        pushfirst!(done, A.job)
        @printf("%5.2f: server %d finished job %d\n", tau(A.c), A.id, A.job)
    end
    A.job = 0
    A.state=Idle()
    event!(A.c, fun(๐’‡!, A, A.state, Setup()), after, rand(ex)/5)
end

๐’‡!(A::Server, ::Idle, ::Setup) = event!(A.c, fun(๐’‡!, A, A.state, Load()), fun(isready, queue))
๐’‡!(A::Server, ๐‘ฅ::๐‘‹, ฮณ::๐ธ) = println(stderr, "$(A.name) $(A.id) undefined transition $๐‘ฅ, $ฮณ")

# model arrivals
function arrive(clk::Clock, job)
    pushfirst!(queue, job)
    event!(clk, fun(arrive, clk, job+1), after, rand(ex))
end

# setup simulation environment and run simulation
Random.seed!(123)
c = Clock()
A = [Server(i, c, Idle(), 0) for i โˆˆ 1:8]
for i โˆˆ shuffle(1:8)
    event!(c, fun(๐’‡!, A[i], A[i].state, Load()), fun(isready, queue))
end
event!(c, fun(arrive, c, 1), after, rand(ex))
run!(c, 10)
0.12: server 4 took job 1
0.41: server 6 took job 2
0.60: server 4 finished job 1
0.68: server 6 finished job 2
1.68: server 1 took job 3
...
9.13: server 2 took job 5
9.28: server 3 finished job 3
9.92: server 5 took job 9
9.95: server 2 finished job 5
"run! finished with 58 clock events, 1001 sample steps, simulation time: 10.0"

Note that we modeled the arrivals "event-based" (without considering any state).