Warning
๐ง Low maintenance. The author currently only responds to pull requests. Don't use master; the current release line is 0.1.7.
๐ญ Why?
Build apps whose features are activated as plugins at runtime โ registration, SMS, social login โ without touching the core source. Each feature becomes an event; anyone can attach plugins to it from outside your app.
โจ Features
- ๐ Events & Hooks โ register plugins for an event; they run in priority + dependency order.
- โก Fast dispatch โ each event compiles to a module, so
Hook.call/3is a direct call: no GenServer, no DB on the read path. - ๐ฉบ Health checks โ optional per-plugin
health_check/0, inspected viaHook.event_health/1. - ๐ Multi-node โ the Mnesia-backed store joins & replicates across a cluster automatically.
- ๐ฆ Runtime installer โ load pre-built
ebinartifacts (local path, URL, or GitHub release). Works in amix release.
๐ Events & Hooks
Define a plugin for an event โ it auto-registers and runs whenever the event is called:
defmodule RegisterEmailSender do
use MishkaInstaller.Event.Hook, event: "after_success_login"
@impl true
def call(entries), do: {:reply, entries}
end
# tweak defaults
use MishkaInstaller.Event.Hook,
event: "after_success_login",
initial: %{depends: [SomeEvent], priority: 20}
Call every plugin registered for an event:
alias MishkaInstaller.Event.Hook
Hook.call("after_success_login", params)
Hook.call("after_success_login", params, private: keep_this) # extra data, untouched by plugins
Hook.call("after_success_login", params, return: true) # return the original input
To start a plugin automatically, add its module to your supervision tree:
children = [RegisterEmailSender, ...]
Note
A plugin's depends always run before it (cycles are rejected at registration), and a plugin can return {:reply, :halt, state} to stop the rest of the chain. See MishkaInstaller.Event.Hook.
๐ฆ Installer
Load an already-compiled ebin at runtime โ no source compilation, so it's release-safe:
alias MishkaInstaller.Installer.Installer
Installer.install(%{app: "demo", version: "0.1.0", type: :path, path: "/ext/demo-0.1.0"})
Installer.install(%{app: "demo", version: "0.1.0", type: :url, path: "https://.../demo-ebin.tar.gz"})
Installer.install(%{app: "demo", version: "0.1.0", type: :github_tag, path: "owner/repo", tag: "0.1.0"})
Installer.install(%{app: "demo", version: "0.1.0", type: :github_latest_release, path: "owner/repo"})
Installer.uninstall(%{app: "demo", version: "0.1.0"})
Note
Remote installs (:url/:github_*) are fail-closed: they require the source host/repo in config :mishka_installer, :allowlist, url_hosts:/github_repos:. Optional checksum: (sha256) pins the artifact; :protected_apps guards apps from being overwritten/removed. See MishkaInstaller.Installer.Installer.
๐ญ Production deployment
An installed library is a pre-built ebin on disk plus a Mnesia record; on every boot it is replayed (put back on the code path and started). So both the ebins and the Mnesia data must live on a persistent (mounted) volume โ otherwise installs do not survive a restart/redeploy. Point both at your volume (here /data):
# config/runtime.exs โ /data is your mounted volume
config :mishka_installer,
project_path: "/data",
extensions_path: "/data/extensions"
config :mishka_installer, MishkaInstaller.MnesiaRepo,
mnesia_dir: "/data/mnesia",
essential: [MishkaInstaller.Event.Event, MishkaInstaller.Installer.Installer]
:extensions_path is where ebins are written; mnesia_dir is where the records live; :essential are the tables created on boot (the plugin and install stores โ keep both). Just depend on :mishka_installer; its supervision tree starts automatically outside :test.
A real release restart proof lives in
test/integration/production_release/โ run it withmix test --only production_release.
๐ Installation
def deps do
[{:mishka_installer, "~> 0.1.7"}]
end
Docs: hexdocs.pm/mishka_installer
๐ Funding & sponsorship
MishkaInstaller is open-source software developed by Mishka Group. If your team or company benefits from it, please consider supporting continued development:
โ Donate / sponsor:github.com/sponsors/mishka-group ยท buymeacoffee.com/mishkagroup
Thank you. ๐
๐ License
Apache License 2.0 โ see LICENSE.
Copyright ยฉ Mishka Group and contributors.