Direct answer
No – a plugin that has already been loaded with Dynlink.loadfile cannot be safely replaced or unloaded while the host process stays running. The runtime keeps the original code and data alive, and there is no API to discard it. Enabling allow_unsafe_modules only turns off safety checks; it does not give you an unload/reload capability.
Confirmed facts
Dynlink.loadfile performs incremental linking via the #load and #run primitives; once a module is linked it remains in the runtime image.
- The runtime provides no
unload operation; the only way to remove a module’s code is to let the process exit.
- Version compatibility requires that the plugin and the host be compiled with exactly the same OCaml version and standard‑library configuration; otherwise you may see
LinkError or segmentation faults.
allow_unsafe_modules disables the safety check that prevents loading of modules that mutate the runtime state, but it does not change the linking model.
Likely explanation (what you can do)
If the plugin is pure and does not retain mutable global or thread‑local state, you can load a newly built .cmxs under a fresh module name and route new requests to it while letting existing requests finish using the old version. The old module stays resident, but as long as no references to it remain it will be garbage‑collected when the process ends. This pattern works only when:
- The plugin exports only functions/values that are captured by the host at call‑site time (no cached closures).
- All mutable state lives outside the plugin (e.g., in a database or external service).
- The host can switch the dispatcher to the new module without needing to unload the old one.
Missing diagnostic detail
Whether the plugin holds mutable global variables or thread‑local storage that must be cleared before the new version can be used safely. If such state exists, the only safe zero‑downtime approach is to run two host instances behind a load balancer and perform a rolling restart.
Steps for a stateless plugin
- Compile the new plugin with the same OCaml version:
ocamlopt -shared -o plugin_new.cmxs plugin.ml
- In the host, load it under a fresh name:
let _ = Dynlink.loadfile "plugin_new.cmxs"
- Obtain the new module’s entry point (e.g., via a registration function) and update the request‑handler to use it for incoming traffic.
- Allow existing requests that were already using the old plugin to complete; no explicit unload is needed.
- If you later wish to free the old module’s memory, ensure no references remain; the runtime will reclaim it on process exit.
When core host modules change
Any change to the host’s own compiled modules (the binary that calls Dynlink) requires a full process restart, because the runtime image of the host cannot be updated incrementally. In that case a rolling restart behind a load balancer is the only viable zero‑downtime strategy.