From e0e9ab76573eb30aaab2b8caf6b4bc765cb7bec4 Mon Sep 17 00:00:00 2001 From: Wojtek Mach Date: Sat, 1 Jun 2019 08:53:24 +0200 Subject: [PATCH 1/2] Mention custom scripts in mix release "One-off commands" docs --- lib/mix/lib/mix/tasks/release.ex | 59 +++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/lib/mix/lib/mix/tasks/release.ex b/lib/mix/lib/mix/tasks/release.ex index 5146145ae20..eb3532bb158 100644 --- a/lib/mix/lib/mix/tasks/release.ex +++ b/lib/mix/lib/mix/tasks/release.ex @@ -112,7 +112,7 @@ defmodule Mix.Tasks.Release do The `eval` command starts its own instance of the VM but without starting any of the applications in the release and without starting distribution. For example, if you need to do some prep work before - running the actual system, like updating your database, `eval` can + running the actual system, like migrating your database, `eval` can be a good fit. Just keep in mind any application you may use during eval has to be explicitly started. @@ -123,6 +123,63 @@ defmodule Mix.Tasks.Release do You can also use `remote` to connect a remote IEx session to the system. + As you operate your system, you may find yourself running some piece of code + as a one-off command quite often and re-typing the whole command every + time may become cumbersome and error prone. For example, suppose you need to + regularly migrate your database and occasionally build a report of currently + connected users. You may consider creating a module to group these tasks: + + # lib/my_app/release_tasks.ex + defmodule MyApp.ReleaseTasks do + def migrate_db() do + # ... + end + + def print_connected_users() do + for user <- connected_users() do + # IO.puts ... + end + end + end + + Again, for migrating the database we'd probably use `eval` but to list + currently connected users we'd probably connect to a running system using + `rpc`: + + bin/RELEASE_NAME eval "MyApp.ReleaseTasks.migrate_db()" + bin/RELEASE_NAME rpc "MyApp.ReleaseTasks.print_connected_users()" + + Finally, you may still automate this further by creating standalone scripts + for these commands. You can do that by adjusting steps in your `mix.exs` + file: + + releases: [ + demo: [ + steps: [:assemble, &create_release_scripts/1] + ] + ] + + defp create_release_scripts(release) do + create_script(release, "eval", "migrate_db", "MyApp.ReleaseTasks.migrate_db()") + create_script(release, "rpc", "print_connected_users", "MyApp.ReleaseTasks.print_connected_users()") + release + end + + defp create_script(release, kind, path, expr) do + %Mix.Release{name: release_name, path: release_path} = release + release_script_path = Path.join([release_path, "bin", to_string(release_name)]) + script_path = Path.join([release_path, "bin", path]) + File.write!(script_path, ~s{#\{release_script_path} #\{kind} "#\{expr}"}) + File.chmod!(script_path, 0o755) + end + + And now running the scripts is as simple as: + + bin/migrate_db + bin/print_connected_users + + See "Steps" section for more information about customizing release assembly. + ### Daemon mode (Unix-like) You can run the release in daemon mode written as a comment: From cd886672dc36096083bd2de96a24fcd2078e010e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 1 Jun 2019 10:52:14 +0200 Subject: [PATCH 2/2] Update release.ex --- lib/mix/lib/mix/tasks/release.ex | 62 +++++++++----------------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/lib/mix/lib/mix/tasks/release.ex b/lib/mix/lib/mix/tasks/release.ex index eb3532bb158..431d9a51ca6 100644 --- a/lib/mix/lib/mix/tasks/release.ex +++ b/lib/mix/lib/mix/tasks/release.ex @@ -123,62 +123,34 @@ defmodule Mix.Tasks.Release do You can also use `remote` to connect a remote IEx session to the system. + #### Helper module + As you operate your system, you may find yourself running some piece of code - as a one-off command quite often and re-typing the whole command every - time may become cumbersome and error prone. For example, suppose you need to - regularly migrate your database and occasionally build a report of currently - connected users. You may consider creating a module to group these tasks: + as a one-off command quite often. You may consider creating a module to group + these tasks: # lib/my_app/release_tasks.ex defmodule MyApp.ReleaseTasks do - def migrate_db() do - # ... + def eval_purge_stale_data() do + # Eval commands needs to start the app before + Application.ensure_all_started(:my_app) + # Code that purges stale data + ... end - def print_connected_users() do - for user <- connected_users() do - # IO.puts ... - end + def rpc_print_connected_users() do + # Code that print users connected to the current running system + ... end end - Again, for migrating the database we'd probably use `eval` but to list - currently connected users we'd probably connect to a running system using - `rpc`: - - bin/RELEASE_NAME eval "MyApp.ReleaseTasks.migrate_db()" - bin/RELEASE_NAME rpc "MyApp.ReleaseTasks.print_connected_users()" - - Finally, you may still automate this further by creating standalone scripts - for these commands. You can do that by adjusting steps in your `mix.exs` - file: - - releases: [ - demo: [ - steps: [:assemble, &create_release_scripts/1] - ] - ] - - defp create_release_scripts(release) do - create_script(release, "eval", "migrate_db", "MyApp.ReleaseTasks.migrate_db()") - create_script(release, "rpc", "print_connected_users", "MyApp.ReleaseTasks.print_connected_users()") - release - end - - defp create_script(release, kind, path, expr) do - %Mix.Release{name: release_name, path: release_path} = release - release_script_path = Path.join([release_path, "bin", to_string(release_name)]) - script_path = Path.join([release_path, "bin", path]) - File.write!(script_path, ~s{#\{release_script_path} #\{kind} "#\{expr}"}) - File.chmod!(script_path, 0o755) - end - - And now running the scripts is as simple as: + In the example above, we prefixed the function names with the command + name used to execute them, but that is entirely optional. - bin/migrate_db - bin/print_connected_users + And to run them: - See "Steps" section for more information about customizing release assembly. + bin/RELEASE_NAME eval "MyApp.ReleaseTasks.eval_purge_stale_data()" + bin/RELEASE_NAME rpc "MyApp.ReleaseTasks.rpc_print_connected_users()" ### Daemon mode (Unix-like)