### Configure Shoehorn Application Settings Source: https://context7.com/nerves-project/shoehorn/llms.txt This configuration example demonstrates how to customize Shoehorn's behavior using the `:shoehorn` application configuration. It shows how to specify applications to start early (`:init`), applications to start last (`:last`), add extra dependencies, set a shutdown timer, and define a custom handler module. ```elixir import Config config :shoehorn, # Start these applications as early as possible init: [:nerves_runtime, :nerves_pack, :system_init], # Applications to start last (default: [:iex]) last: [:iex], # Add extra dependencies not in mix.exs extra_dependencies: [ {:my_app, [:some_hidden_dependency]} ], # Shutdown timer for handler callbacks (default: 30_000 ms) shutdown_timer: 50_000, # Custom handler module (default: Shoehorn.DefaultHandler) handler: MyApp.ShoehornHandler ``` -------------------------------- ### Create Release and Start with Shoehorn Source: https://github.com/nerves-project/shoehorn/blob/main/README.md Commands to build the release and start the application using the custom Shoehorn boot script. ```bash mix release RELEASE_BOOT_SCRIPT=shoehorn _build/dev/rel/simple_app/bin/simple_app start_iex ``` -------------------------------- ### Build and Run Shoehorn Release Source: https://github.com/nerves-project/shoehorn/blob/main/example/README.md Commands to fetch dependencies, compile the release, and start the application with the Shoehorn boot script in an interactive shell. ```bash cd my_project mix deps.get mix release RELEASE_BOOT_SCRIPT=shoehorn _build/dev/rel/my_project/bin/my_project start_iex ``` -------------------------------- ### Start Shoehorn Release via CLI Source: https://context7.com/nerves-project/shoehorn/llms.txt Instructions for building and starting a Nerves release using the custom Shoehorn boot script via the RELEASE_BOOT_SCRIPT environment variable. ```bash mix release.init mix release RELEASE_BOOT_SCRIPT=shoehorn _build/dev/rel/my_app/bin/my_app start_iex RELEASE_BOOT_SCRIPT=shoehorn _build/dev/rel/my_app/bin/my_app daemon ``` -------------------------------- ### Implement Shoehorn Handler Callbacks Source: https://context7.com/nerves-project/shoehorn/llms.txt Demonstrates the implementation of the Shoehorn.Handler behaviour. Includes init/1 for state setup, application_started/2 for telemetry, and application_exited/3 for recovery logic. ```elixir @impl Shoehorn.Handler def init(opts) do shutdown_timer = Keyword.get(opts, :shutdown_timer, 30_000) {:ok, %{restart_attempts: %{}, shutdown_timer: shutdown_timer, telemetry_enabled: true}} end @impl Shoehorn.Handler def application_started(app, state) do Logger.info("Application #{inspect(app)} started successfully") if state.telemetry_enabled do :telemetry.execute([:shoehorn, :app, :started], %{}, %{app: app}) end new_attempts = Map.put(state.restart_attempts, app, 0) {:continue, %{state | restart_attempts: new_attempts}} end @impl Shoehorn.Handler def application_exited(:ssh, reason, state) do Logger.warning("SSH crashed: #{inspect(reason)}, restarting...") Process.sleep(1000) Application.ensure_all_started(:ssh) {:continue, state} end ``` -------------------------------- ### Implement Custom Shoehorn Failure Handler Source: https://github.com/nerves-project/shoehorn/blob/main/README.md An example of a custom Shoehorn handler module implementing the `Shoehorn.Handler` behavior. This module defines specific actions for application start and exit events, including restarting the `:ssh` application when it exits abnormally and logging other application exits. ```elixir defmodule Example.RestartHandler do @behavior Shoehorn.Handler def init(_opts) do {:ok, :no_state} end def application_started(_app, state) do {:continue, state} end def application_exited(:ssh, _reason, state) do Logger.error("Stop bothering ssh!") Process.sleep(1000) Application.ensure_all_started(:ssh) {:continue, state} end def application_exited(app, _reason, state) do Logger.error("Application stopped! #{inspect(app)} #{inspect(state)}") {:halt, state} end end ``` -------------------------------- ### Install SomeApp dependency in mix.exs Source: https://github.com/nerves-project/shoehorn/blob/main/example/some_app/README.md Adds the SomeApp package to the project's dependency list. This allows the application to utilize the library functions by specifying the version requirement. ```elixir def deps do [ {:some_app, "~> 0.1.0"} ] end ``` -------------------------------- ### Install OptionalApp Dependency in Mix.exs Source: https://github.com/nerves-project/shoehorn/blob/main/example/optional_app/README.md This snippet shows how to add the OptionalApp package as a dependency in your Elixir project's mix.exs file. Ensure you have the latest version compatible with your project. ```elixir def deps do [ {:optional_app, "~> 0.1.0"} ] end ``` -------------------------------- ### Implement Shoehorn Recovery Handler Source: https://context7.com/nerves-project/shoehorn/llms.txt Custom implementation of the Shoehorn.Handler behaviour to manage application lifecycle and recovery. It defines how the system should react to application starts and exits, including critical recovery procedures for Nerves runtime components. ```Elixir defmodule MyNervesApp.RecoveryHandler do @behaviour Shoehorn.Handler require Logger def init(_opts) do {:ok, %{in_recovery: false}} end def application_started(app, state) do Logger.info("[Recovery] #{app} started") {:continue, state} end # Keep network stack alive - critical for OTA updates def application_exited(app, reason, state) when app in [:nerves_runtime, :nerves_pack] do Logger.error("[Recovery] Critical app #{app} exited: #{inspect(reason)}, restarting") Process.sleep(500) Application.ensure_all_started(app) {:continue, state} end # Main app failure - enter recovery mode def application_exited(:my_nerves_app, reason, state) do Logger.error("[Recovery] Main app crashed: #{inspect(reason)}") Logger.info("[Recovery] Entering recovery mode - device will accept OTA updates") # Don't restart, just wait for firmware update via network {:continue, %{state | in_recovery: true}} end def application_exited(app, reason, state) do Logger.warning("[Recovery] #{app} exited: #{inspect(reason)}") {:continue, state} end end ``` -------------------------------- ### Implement Custom Shoehorn.Handler Behaviour Source: https://context7.com/nerves-project/shoehorn/llms.txt This Elixir code defines a custom handler module that implements the `Shoehorn.Handler` behaviour. It includes callbacks for initializing the handler state, logging application start events, and defining a custom strategy for handling application exits, including restarting non-critical applications and halting the system after repeated failures. ```elixir defmodule MyApp.ShoehornHandler do @behaviour Shoehorn.Handler require Logger @impl Shoehorn.Handler def init(_opts) do # Initialize handler state {:ok, %{restart_counts: %{}, max_restarts: 3}} end @impl Shoehorn.Handler def application_started(app, state) do Logger.info("[Shoehorn] Application started: #{inspect(app)}") # Reset restart count when application starts successfully new_counts = Map.put(state.restart_counts, app, 0) {:continue, %{state | restart_counts: new_counts}} end @impl Shoehorn.Handler def application_exited(:non_critical_app, reason, state) do # Ignore non-critical app failures Logger.warning("[Shoehorn] Non-critical app exited: #{inspect(reason)}") {:continue, state} end def application_exited(app, reason, state) do count = Map.get(state.restart_counts, app, 0) if count < state.max_restarts do Logger.warning("[Shoehorn] #{app} exited (#{inspect(reason)}), restarting (attempt #{count + 1})") # Wait a bit before restarting Process.sleep(1000) Application.ensure_all_started(app) new_counts = Map.put(state.restart_counts, app, count + 1) {:continue, %{state | restart_counts: new_counts}} else Logger.error("[Shoehorn] #{app} failed #{state.max_restarts} times, halting system") {:halt, state} end end end ``` -------------------------------- ### Configure Application Initialization Order Source: https://github.com/nerves-project/shoehorn/blob/main/README.md Use the :init configuration in config.exs to prioritize specific OTP applications during the boot sequence. ```elixir config :shoehorn, init: [:nerves_runtime, :nerves_pack] ``` -------------------------------- ### Configure Mix Release with Shoehorn.Release.init/1 Source: https://context7.com/nerves-project/shoehorn/llms.txt This snippet shows how to integrate Shoehorn into your Mix project's release configuration by adding `Shoehorn.Release.init/1` to the release steps. This enables custom application startup ordering and failure handling. It also demonstrates how to use the `applications` option for advanced control over application loading. ```elixir defmodule MyApp.MixProject do use Mix.Project def project do [ app: :my_app, version: "0.1.0", elixir: "~> 1.15", start_permanent: Mix.env() == :prod, deps: deps(), releases: releases() ] end def application do [ extra_applications: [:logger], mod: {MyApp.Application, []} ] end defp deps do [ {:shoehorn, "~> 0.9.3"} ] end def releases do [ my_app: [ steps: [&Shoehorn.Release.init/1, :assemble], # Optional: control application start modes applications: [ # Load but don't start this app load_only_app: :load ] ] ] end end ``` -------------------------------- ### Configure Shoehorn Settings in config.exs Source: https://context7.com/nerves-project/shoehorn/llms.txt Sets up Shoehorn's configuration, including the applications to initialize, the custom recovery handler, and the shutdown timer. This ensures Shoehorn behaves as expected during application startup and shutdown. ```Elixir import Config config :shoehorn, init: [:nerves_runtime, :nerves_pack], handler: MyNervesApp.RecoveryHandler, shutdown_timer: 60_000 ``` -------------------------------- ### Handle Application Stops and Restarts Source: https://github.com/nerves-project/shoehorn/blob/main/example/README.md Demonstrates stopping an application in the IEx shell and observing the restart behavior managed by Shoehorn handlers. ```elixir iex> Application.stop(:my_project) :ok iex> Application stopped: :my_project %{restart_counts: 0} MyProject start Application started: :my_project ``` ```elixir iex> Application.stop(:my_project) 15:37:58.192 [info] Application my_project exited: :stopped Application stopped forever: :my_project %{restart_counts: 4} :ok ``` -------------------------------- ### Configure Shoehorn in mix.exs Source: https://github.com/nerves-project/shoehorn/blob/main/README.md Add Shoehorn to your project dependencies and configure the release steps to include the Shoehorn initialization process. ```elixir def project do [ ... releases: releases() ] end def releases do [ simple_app: [ steps: [&Shoehorn.Release.init/1, :assemble] ] ] end defp deps do [ {:shoehorn, "~> 0.9.2"} ] end ``` -------------------------------- ### Configure Shoehorn Release in mix.exs Source: https://context7.com/nerves-project/shoehorn/llms.txt Defines the project's dependencies and release configuration, specifying Shoehorn's role in the release process. It includes setting up Shoehorn's initialization steps and critical applications. ```Elixir defmodule MyNervesApp.MixProject do use Mix.Project def project do [ app: :my_nerves_app, version: "0.1.0", elixir: "~> 1.15", deps: deps(), releases: releases() ] end defp deps do [ {:shoehorn, "~> 0.9.3"}, {:nerves_runtime, "~> 0.13"}, {:nerves_pack, "~> 0.7"} ] end def releases do [ my_nerves_app: [ steps: [&Shoehorn.Release.init/1, :assemble], shoehorn: [ init: [:nerves_runtime, :nerves_pack], extra_dependencies: [] ] ] ] end end ``` -------------------------------- ### Configure Custom Shoehorn Handler Source: https://github.com/nerves-project/shoehorn/blob/main/README.md This configuration snippet shows how to specify a custom handler module for Shoehorn in the production environment. This allows overriding the default behavior for handling application failures. ```elixir # config/prod.exs config :shoehorn, handler: SimpleApp.ShoehornHandler ``` -------------------------------- ### Shoehorn Default Handler Implementation Source: https://context7.com/nerves-project/shoehorn/llms.txt The default handler implementation provided by Shoehorn, which ignores application failures and allows the system to continue running. ```elixir defmodule Shoehorn.DefaultHandler do @behaviour Shoehorn.Handler @impl Shoehorn.Handler def init(_opts), do: {:ok, :no_state} @impl Shoehorn.Handler def application_started(_app, state), do: {:continue, state} @impl Shoehorn.Handler def application_exited(_app, _reason, state), do: {:continue, state} end ``` -------------------------------- ### Add CrashApp dependency to mix.exs Source: https://github.com/nerves-project/shoehorn/blob/main/example/crash_app/README.md This snippet demonstrates how to add the crash_app package to the dependencies list in an Elixir project's mix.exs file. It specifies the version requirement using the ~> operator. ```elixir def deps do [ {:crash_app, "~> 0.1.0"} ] end ``` -------------------------------- ### Configure Shoehorn Shutdown Timer Source: https://github.com/nerves-project/shoehorn/blob/main/README.md This configuration snippet demonstrates how to adjust the shutdown timer for Shoehorn's handler callbacks. This value determines the maximum time allowed for a callback to execute before the node is instructed to halt. ```elixir # config/config.exs config :shoehorn, shutdown_timer: 50_000 # 50 Seconds ``` -------------------------------- ### Configure Shoehorn Failure Handler Source: https://github.com/nerves-project/shoehorn/blob/main/CHANGELOG.md Configures the Shoehorn handler to ignore application exits, preventing the node from halting on failure. This is typically used in development environments to keep the node running when an application stops. ```elixir config :shoehorn, handler: Shoehorn.Handler.Ignore ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.