Skip to content

Commit

Permalink
Add an extension to support Revise
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesWrigley committed Jan 2, 2025
1 parent 764ceec commit 914e50c
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 5 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
version:
- 'nightly'
- '1'
- '1.9'
- '1.10'
os:
- ubuntu-latest
- macOS-latest
Expand All @@ -36,8 +36,6 @@ jobs:
exclude:
- os: macOS-latest
arch: x86
- os: windows-latest # Killing workers doesn't work on windows in 1.9
version: '1.9'

steps:
- uses: actions/checkout@v4
Expand Down
11 changes: 9 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
Sockets = "6462fe0b-24de-5631-8697-dd941f90decc"

[weakdeps]
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"

[extensions]
ReviseExt = "Revise"

[compat]
Distributed = "1"
Random = "1"
Revise = "3.7.0"
Serialization = "1"
Sockets = "1"
julia = "1.9"
julia = "1.10"

[extras]
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
Expand All @@ -21,4 +28,4 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["LinearAlgebra", "Test", "LibSSH", "Distributed"]
test = ["LinearAlgebra", "Test", "LibSSH", "Distributed", "Revise"]
1 change: 1 addition & 0 deletions docs/src/_changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This documents notable changes in DistributedNext.jl. The format is based on
- [`other_workers()`](@ref) and [`other_procs()`](@ref) were implemented and
exported ([#18]).
- Implemented callback support for workers being added/removed etc ([#17]).
- Added a package extension to support Revise.jl ([#17]).

## [v1.0.0] - 2024-12-02

Expand Down
30 changes: 30 additions & 0 deletions ext/ReviseExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module ReviseExt

import DistributedNext
import DistributedNext: myid, workers, remotecall

import Revise


struct DistributedNextWorker <: Revise.AbstractWorker
id::Int
end

function get_workers()
map(DistributedNextWorker, workers())
end

function Revise.remotecall_impl(f, worker::DistributedNextWorker, args...; kwargs...)
remotecall(f, worker.id, args...; kwargs...)
end

Revise.is_master_worker(::typeof(get_workers)) = myid() == 1
Revise.is_master_worker(worker::DistributedNextWorker) = worker.id == 1

function __init__()
Revise.register_workers_function(get_workers)
DistributedNext.add_worker_started_callback(pid -> Revise.init_worker(DistributedNextWorker(pid));
key="DistributedNext-integration")
end

end
64 changes: 64 additions & 0 deletions test/distributed_exec.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

import Revise
using DistributedNext, Random, Serialization, Sockets
import DistributedNext
import DistributedNext: launch, manage
Expand Down Expand Up @@ -2004,6 +2005,69 @@ end
@test exit_state == DistributedNext.WorkerState_exterminated
end

# This is a simplified copy of a test from Revise.jl's tests
@testset "Revise.jl integration" begin
function rm_precompile(pkgname::AbstractString)
filepath = Base.cache_file_entry(Base.PkgId(pkgname))
isa(filepath, Tuple) && (filepath = filepath[1]*filepath[2]) # Julia 1.3+
for depot in DEPOT_PATH
fullpath = joinpath(depot, filepath)
isfile(fullpath) && rm(fullpath)
end
end

pid = only(addprocs(1))

# Test that initialization succeeds by checking that Main.whichtt is defined
# on the worker, which is defined by Revise.init_worker().
@test timedwait(() ->remotecall_fetch(() -> hasproperty(Main, :whichtt), pid), 10) == :ok

tmpdir = mktempdir()
@everywhere push!(LOAD_PATH, $tmpdir) # Don't want to share this LOAD_PATH

# Create a fake package
module_file = joinpath(tmpdir, "ReviseDistributed", "src", "ReviseDistributed.jl")
mkpath(dirname(module_file))
write(module_file,
"""
module ReviseDistributed
f() = π
g(::Int) = 0
end
""")

# Check that we can use it
@everywhere using ReviseDistributed
for p in procs()
@test remotecall_fetch(ReviseDistributed.f, p) == π
@test remotecall_fetch(ReviseDistributed.g, p, 1) == 0
end

# Test changing and deleting methods
write(module_file,
"""
module ReviseDistributed
f() = 3.0
end
""")
Revise.revise()
for p in procs()
# We use timedwait() here because worker updates from Revise are asynchronous
@test timedwait(() -> remotecall_fetch(ReviseDistributed.f, p) == 3.0, 10) == :ok

@test_throws RemoteException remotecall_fetch(ReviseDistributed.g, p, 1)
end

rmprocs(workers())
rm_precompile("ReviseDistributed")
pop!(LOAD_PATH)
end


# Run topology tests last after removing all workers, since a given
# cluster at any time only supports a single topology.
if nprocs() > 1
Expand Down

0 comments on commit 914e50c

Please sign in to comment.