# How can I stop a Gurobi solve in JuMP in real time (like Ctrl+C) and still keep the solution?

**URL:** <https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841>\
**Category:** Optimization (Mathematical)\
**Tags:** question, jump, gurobi\
**Created:** [October 3, 2025, 4:43am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841 "2025-10-03T04:43:06Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![amit\_97](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amit_97/32/224072_2.png) [@amit\_97](https://discourse.julialang.org/u/amit_97)\
**Post date:** [October 3, 2025, 4:43am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/1 "2025-10-03T04:43:06Z")

</div>

I am using **JuMP with Gurobi.jl** to solve a MIP.

In Julia, pressing **Ctrl+C** usually kills the entire Julia process instead of just stopping Gurobi.

My goal is:

- Stop the optimization at any arbitrary time (not using `MIPGap`, `TimeLimit`, or `NodeLimit`).
- Still retrieve the best feasible solution found so far.

I’ve seen that Gurobi supports callbacks via JuMP/MOI. Is it possible to have something like a **user interrupt (e.g., pressing a key) that triggers a callback to terminate the solver gracefully**?

If yes, could someone show me the **minimal working example** of how to set this up in Julia?

Thanks!

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [October 3, 2025, 5:51am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/2 "2025-10-03T05:51:21Z")

</div>

> [@amit\_97](#):
>
> In Julia, pressing **Ctrl+C** usually kills the entire Julia process instead of just stopping Gurobi.

Please press _once_.

e.g.

```julia
import JuMP, Gurobi, SparseArrays
N = 50 # 754 seconds
Q = 1. * SparseArrays.dropzeros(
    SparseArrays.spdiagm(
        [i => rand(-9:9, N - i) for i in 0:div(N, 2)]...
    )
)
m = JuMP.Model();
JuMP.@variable(m, rand(-7:-3) <= y[1:N] <= rand(3:7));
JuMP.@variable(m, rand(-9:-5) <= x[1:N] <= rand(5:9));
JuMP.@objective(m, Min, (x'Q)y);
JuMP.set_optimizer(m, Gurobi.Optimizer)
JuMP.optimize!(m); JuMP.solution_summary(m)

```

test:

```julia
julia> JuMP.optimize!(m); JuMP.solution_summary(m)
Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - "Debian GNU/Linux 12 (bookworm)")

CPU model: AMD EPYC 7763 64-Core Processor, instruction set [SSE2|AVX|AVX2]
Thread count: 128 physical cores, 256 logical processors, using up to 32 threads

Optimize a model with 0 rows, 100 columns and 0 nonzeros
Model fingerprint: 0x8f14f73d
Model has 927 quadratic objective terms
Coefficient statistics:
  Matrix range [0e+00, 0e+00]
  Objective range [0e+00, 0e+00]
  QObjective range [2e+00, 2e+01]
  Bounds range [3e+00, 9e+00]
  RHS range [0e+00, 0e+00]

Continuous model is non-convex -- solving as a MIP

Found heuristic solution: objective 1972.0000000
Found heuristic solution: objective -90.0000000
Presolve removed 0 rows and 5 columns
Presolve time: 0.01s
Presolved: 921 rows, 1016 columns, 2763 nonzeros
Found heuristic solution: objective -1365.000000
Variable types: 0 continuous, 1016 integer (1016 binary)

Root relaxation: objective -1.668040e+05, 396 iterations, 0.00 seconds (0.00 work units)

    Nodes | Current Node | Objective Bounds | Work
 Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time

     0 0 -166804.00 0 95 -1365.0000 -166804.00 - - 0s
H 0 0 -31392.00000 -166804.00 431% - 0s
H 0 0 -42554.00000 -166804.00 292% - 0s
H 0 0 -44102.00000 -166804.00 278% - 0s
H 0 0 -45200.00000 -166804.00 269% - 0s
     0 0 -154413.00 0 127 -45200.000 -154413.00 242% - 0s
     0 0 -148261.00 0 145 -45200.000 -148261.00 228% - 0s
     0 0 -148189.50 0 145 -45200.000 -148189.50 228% - 0s
     0 2 -148189.50 0 145 -45200.000 -148189.50 228% - 0s
H 31 64 -46492.00000 -134496.00 189% 132 0s
H 50 64 -47016.00000 -133618.25 184% 121 0s
H 51 64 -47256.00000 -133215.88 182% 121 0s
H 511 542 -48548.00000 -129601.50 167% 82.7 0s
H 545 689 -48697.00000 -129601.50 166% 82.5 0s
H 572 689 -49412.00000 -129601.50 162% 82.1 0s
* 1639 1572 40 -50381.00000 -128661.00 155% 69.6 0s
* 1640 1572 40 -50573.00000 -128661.00 154% 69.6 0s
* 1642 1572 38 -54946.00000 -128661.00 134% 69.5 0s
H 1794 1693 -57200.00000 -128596.63 125% 69.3 0s
H 1990 1823 -57215.00000 -128479.25 125% 69.1 0s
H 1994 1823 -57981.00000 -128479.25 122% 69.1 0s
H 2020 1823 -58562.00000 -128479.25 119% 69.0 0s
H 2083 1823 -59088.00000 -128479.25 117% 69.1 0s
H 2160 1985 -60250.00000 -128479.25 113% 69.2 0s
H 2340 2000 -60908.00000 -127924.75 110% 69.3 0s
H 2755 2220 -62933.00000 -127388.67 102% 68.3 0s
H 3141 2478 -63149.00000 -126541.00 100% 67.1 0s
 58996 26304 -84114.500 28 813 -63149.000 -94544.362 49.7% 42.3 5s
^C
Cutting planes:
  Gomory: 42
  Flow cover: 340
  Zero half: 366
  RLT: 7
  BQP: 4

Explored 59003 nodes (2510577 simplex iterations) in 7.97 seconds (10.92 work units)
Thread count was 32 (of 256 available processors)

Solution count 10: -63149 -62933 -60908 ... -54946

Solve interrupted
Best objective -6.314900000000e+04, best bound -8.731000000000e+04, gap 38.2603%

User-callback calls 119146, time in user-callback 0.02 sec
solution_summary(; result = 1, verbose = false)
├ solver_name : Gurobi
├ Termination
│ ├ termination_status : INTERRUPTED
│ ├ result_count : 10
│ ├ raw_status : Optimization was terminated by the user.
│ └ objective_bound : -8.73100e+04
├ Solution (result = 1)
│ ├ primal_status : FEASIBLE_POINT
│ ├ dual_status : NO_SOLUTION
│ ├ objective_value : -6.31490e+04
│ └ relative_gap : 3.82603e-01
└ Work counters
  ├ solve_time (sec) : 7.99659e+00
  ├ simplex_iterations : 2510577
  ├ barrier_iterations : 0
  └ node_count : 59003

julia> JuMP.value.(x)
50-element Vector{Float64}:

```

> [@amit\_97](#):
>
> In Julia, pressing **Ctrl+C** usually kills the entire Julia process

This is not correct either, you can refer to [The Julia REPL · The Julia Language](https://docs.julialang.org/en/v1/stdlib/REPL/#Key-bindings)

---

<div class="post-metadata">

**Author:** ![amit\_97](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amit_97/32/224072_2.png) [@amit\_97](https://discourse.julialang.org/u/amit_97)\
**Post date:** [October 3, 2025, 6:53am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/3 "2025-10-03T06:53:12Z")

</div>

> [@amit\_97](#):
>
> In Julia, pressing **Ctrl+C** usually kills the entire Julia process

no, it is not working. and i want to add one more thing, i’m using server base gurobi license, not on local machine.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [October 3, 2025, 7:09am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/4 "2025-10-03T07:09:14Z")

</div>

> [@amit\_97](#):
>
> Stop the optimization at any arbitrary time (not using `MIPGap`, `TimeLimit`, or `NodeLimit`).

I think the requirement is somewhat unusual.  
But you can use `GRBterminate(backend(model))` within a callback, as written in [GitHub - jump-dev/Gurobi.jl: A Julia interface to the Gurobi Optimizer · GitHub](https://github.com/jump-dev/Gurobi.jl#callbacks).  
As for achieving your “arbitrary” goal…  
Since I have no idea what a cloud solve is like… But in julia maybe you can try some asynchronous programming thing:

```julia
import JuMP, Gurobi, SparseArrays
N = 50 # 754 seconds
Q = 1. * SparseArrays.dropzeros(
    SparseArrays.spdiagm(
        [i => rand(-9:9, N - i) for i in 0:div(N, 2)]...
    )
);
m = JuMP.direct_model(Gurobi.Optimizer())
JuMP.@variable(m, rand(-7:-3) <= y[1:N] <= rand(3:7));
JuMP.@variable(m, rand(-9:-5) <= x[1:N] <= rand(5:9));
JuMP.@objective(m, Min, (x'Q)y);

# Run the solve async-ly
Threads.@spawn JuMP.optimize!(m)

# when you want to interrupt, execute this command in the REPL
Gurobi.GRBterminate(JuMP.backend(m))

# you can check the current status
JuMP.solution_summary(m)
JuMP.value.(x)

```

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [October 4, 2025, 12:02am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/5 "2025-10-04T00:02:18Z")

</div>

Hi @amit_97, welcome to the forum 😄

> i’m using server base gurobi license, not on local machine.

Do you mean the Gurobi instant cloud? Or just the WLS license?

If you’re using the Gurobi instant cloud, the Gurobi documentation sounds like it should support termination, so if CTRL+C isn’t working, then that is a bug we should fix: [Callbacks - Gurobi Remote Services Guide](https://docs.gurobi.com/projects/remoteservices/en/12.0/content/programming-with-remote-services/callbacks.html#seccscallbacks)

Do you have a reproducible example of your model? What options did you set? (You shouldn’t are any sensitive API keys, etc.)

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [October 4, 2025, 1:10am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/7 "2025-10-04T01:10:43Z")

</div>

We trap the interrupt and call GRBterminate: [Gurobi.jl/src/MOI\_wrapper/MOI\_callbacks.jl at 19882cf814f5438dc8a339c06f7f2c416612b156 · jump-dev/Gurobi.jl · GitHub](https://github.com/jump-dev/Gurobi.jl/blob/19882cf814f5438dc8a339c06f7f2c416612b156/src/MOI_wrapper/MOI_callbacks.jl#L45)

Let’s please wait for Amit to reply.

---

<div class="post-metadata">

**Author:** ![amit\_97](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amit_97/32/224072_2.png) [@amit\_97](https://discourse.julialang.org/u/amit_97)\
**Post date:** [October 6, 2025, 4:15am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/8 "2025-10-06T04:15:33Z")

</div>

Hello @odow, thank you for your response. However, I’m experiencing an issue specifically with VS Code and its integrated terminal. When I run the code through the VS Code terminal, it doesn’t accept any input or respond until Gurobi finishes solving. In contrast, when I execute the same code via PowerShell, the “Ctrl + C” interrupt command works as expected.

---

<div class="post-metadata">

**Author:** ![amit\_97](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amit_97/32/224072_2.png) [@amit\_97](https://discourse.julialang.org/u/amit_97)\
**Post date:** [October 6, 2025, 4:18am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/9 "2025-10-06T04:18:59Z")

</div>

**property of VS Code terminal:**  
Command line: C:\Users\xyz\AppData\Local\Programs\Julia-1.10.9\bin\julia.exe  
-i --banner=no --project=C:\Users\xyz.julia\environments\v1.10 c:\Users\xyz.cursor\extensions\julialang.language-julia-1.149.2-universal\scripts\terminalserver\terminalserver.jl  
.\pipe\vsc-jl-repl-e177509b-df29-4d52-9441-08472c4f840a  
.\pipe\vsc-jl-repldbg-033bc92e-4781-4c7e-b229-9f8308e2fccb  
.\pipe\vsc-jl-cr-d830131c-4d65-4ce2-b12f-a2372fab5eac USE\_REVISE=true  
USE\_PLOTPANE=true USE\_PROGRESS=true  
ENABLE\_SHELL\_INTEGRATION=true  
DEBUG\_MODE=false

**property of PowerShell terminal:**

Command line: C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe  
-noexit -command ‘try { . “c:\Users\xyz\AppData\Local\Programs\cursor\resources\app\out\vs\workbench\contrib\terminal\common\scripts\shellIntegration.ps1” } catch {}’

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [October 6, 2025, 7:08am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/10 "2025-10-06T07:08:24Z")

</div>

It seems like there are a number of issues with CTRL+C in vs code: [GitHub · Where software is built](https://github.com/julia-vscode/julia-vscode/issues?q=is%3Aissue%20state%3Aopen%20ctrl%2Bc)

If you want to intercept, I’d just use powershell.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [October 6, 2025, 12:55pm UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/11 "2025-10-06T12:55:32Z")

</div>

VSCode in windows works fine, really. It is one of the greatest softwares in my mind.  
(BTW, windows users probably use the powershell integrated in VSCode—it is powershell after all)

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [October 20, 2025, 1:24am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/12 "2025-10-20T01:24:06Z")

</div>

I find the API `GRBterminate` exceptionally useful, particularly working in conjunction with julia’s async programming.

e.g. terminate a vector of models and retrieve the available best solutions.

```julia
import JuMP, Gurobi, SparseArrays
const GRB_ENV = Gurobi.Env();
const Ns = 20:60;
const J = length(Ns);
const inn = Vector{JuMP.Model}(undef, J);
const TLIM = 4;
function opt_and_assert(j)
    m = inn[j]
    JuMP.optimize!(m)
    t, p = JuMP.termination_status(m), JuMP.primal_status(m)
    p == JuMP.FEASIBLE_POINT || error("primal: $p")
    t in [JuMP.OPTIMAL, JuMP.INTERRUPTED] || error("termination: $t")
    print("\r j = $j is done")
end
interrupt_opt(j) = Gurobi.GRBterminate(JuMP.backend(inn[j]))
function build_model(j, N)
    Q = 1. * SparseArrays.dropzeros(
        SparseArrays.spdiagm(
            [i => rand(-9:9, N - i) for i in 0:div(N, 2)]...
        )
    )
    m = inn[j] = JuMP.direct_model(Gurobi.Optimizer(GRB_ENV))
    JuMP.set_silent(m)
    JuMP.@variable(m, rand(-7:-3) <= y[1:N] <= rand(3:7));
    JuMP.@variable(m, rand(-9:-5) <= x[1:N] <= rand(5:9));
    JuMP.@objective(m, Min, (x'Q)y)
    print("\r built j = $j, N = $N")
end;
# build_model
wvec = map((j, N) -> Threads.@spawn(build_model(j, N)), 1:J, Ns);
foreach(wait, wvec)
# optimize model within a TimeLimit
cvec = map(j -> Threads.@spawn(opt_and_assert(j)), 1:J);
sleep(TLIM)
# interrupt manually
foreach(interrupt_opt, 1:J)
# check the best available results
foreach(wait, cvec)
map(JuMP.termination_status, inn)
map(JuMP.objective_value, inn)

```

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [October 20, 2025, 1:47am UTC](https://discourse.julialang.org/t/how-can-i-stop-a-gurobi-solve-in-jump-in-real-time-like-ctrl-c-and-still-keep-the-solution/132841/13 "2025-10-20T01:47:50Z")

</div>

Your code is not safe. It uses `GRB_ENV` across multiple threads.

A better way to write this code would be:

```julia
using JuMP
import Gurobi
import SparseArrays

function build_model(N, should_terminate)
    Q = SparseArrays.spdiagm(
        [i => rand(-9:9, N - i) for i in 0:div(N, 2)]...
    )
    SparseArrays.dropzeros!(Q)
    model = direct_model(Gurobi.Optimizer())
    set_silent(model)
    @variable(model, rand(-7:-3) <= y[1:N] <= rand(3:7))
    @variable(model, rand(-9:-5) <= x[1:N] <= rand(5:9))
    @objective(model, Min, (x' * Q) * y)
    function my_callback_function(cb_data, cb_where::Cint)
        if should_terminate[]
            Gurobi.GRBterminate(backend(model))
        end
    end
    set_attribute(model, Gurobi.CallbackFunction(), my_callback_function)
    optimize!(model)
    return model
end

function main()
    should_terminate = Threads.Atomic{Bool}(false)
    tasks = map(N -> Threads.@spawn(build_model(N, should_terminate)), 20:60)
    sleep(4.0)
    should_terminate[] = true
    models = fetch.(tasks)
    @show termination_status.(models)
    @show primal_status.(models)
    return
end

```

but you’re spawning a lot of threads here.
