Skip to content

Commit a8cc8d8

Browse files
authored
Merge pull request #201 from tompave/no_application
Remove the Application module
2 parents c42e33a + af1850c commit a8cc8d8

File tree

6 files changed

+30
-89
lines changed

6 files changed

+30
-89
lines changed

.iex.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,16 @@ cacheinfo = fn() ->
5757
:ets.i(:fun_with_flags_cache)
5858
end
5959

60+
# Start the FWF Supervision tree as a child of the IEx application.
61+
# This makes it a bit more convenient to visualize the supervision tree in the
62+
# observer tool. (`:observer.start()`)
63+
#
64+
Supervisor.start_child(IEx.Supervisor, {FunWithFlags.Supervisor, []})
65+
#
66+
# Or starting it directly also works:
67+
#
68+
# FunWithFlags.Supervisor.start_link(nil)
69+
70+
# Enable this to work with telemetry events:
71+
#
6072
# FunWithFlags.Telemetry.attach_debug_handler()

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
Work is in progress towards v2.0 of the package.
66

7+
* Start behaviour has changed. FunWithFlags v2.0 doesn't come with its own Application anymore, therefore its supervision tree should be started and managed manually. The ability to manually control FunWithFlags' supervision tree was initially introduced in [v1.7.0](https://github.com/tompave/fun_with_flags/blob/master/CHANGELOG.md#v170), and has now become the default and only way to use the package. ([pull/201](https://github.com/tompave/fun_with_flags/pull/201))
8+
79
Main goals:
810

911
* [ ] Config overhaul. Stop using the config.exs file, and rather do something like what Ecto does. The host application should define its own module (like an Ecto repo) that provides the flag querying and toggling API. The package config should be provided with an init callback in the custom module.
10-
* [ ] Start behaviour. It should never start automatically, so the manual management of the supervision tree should become the default.
1112
* [ ] Stop relying on atoms. Use binaries wherever possible. Relying on atoms makes some things harder, especially when handling user input in the UI package.
1213
* [ ] Add metadata to the storage layer: timestamps, plus free form JSON for later use.
1314

README.md

Lines changed: 12 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ It stores flag information in Redis or a relational DB (PostgreSQL, MySQL, or SQ
5151
* [Extensibility](#extensibility)
5252
- [Custom Persistence Adapters](#custom-persistence-adapters)
5353
* [Telemetry](#telemetry)
54-
* [Application Start Behaviour](#application-start-behaviour)
5554
* [Testing](#testing)
5655
* [Development](#development)
5756
- [Working with PubSub Locally](#working-with-pubsub-locally)
@@ -520,11 +519,20 @@ def deps do
520519
end
521520
```
522521

523-
Using `ecto_sql` for persisting the flags also requires an ecto adapter, e.g. `postgrex`, `mariaex` or `myxql`. Please refer to the Ecto documentation for the details.
522+
Using `ecto_sql` for persisting the flags also requires an ecto adapter, e.g. `postgrex`, `myxql`, or `ecto_sqlite3`. Please refer to the Ecto documentation for the details.
524523

525-
Since FunWithFlags depends on an Elixir more recent than 1.4, there is [no need to explicitly declare the application](https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#application-inference).
524+
FunWithFlags comes with its own supervision tree that needs to be started in order to use the package. This can be as simple as including `FunWithFlags.Supervisor` in the supervision tree of the host application:
526525

527-
If you need to customize how the `:fun_with_flags` application is loaded and started, refer to the [Application Start Behaviour](#application-start-behaviour) section, below in this document.
526+
```elixir
527+
def start(_type, _args) do
528+
children = [
529+
FunWithFlags.Supervisor,
530+
]
531+
532+
...
533+
```
534+
535+
When using FunWithFlags in a Phoenix application, it's recommended to start `FunWithFlags.Supervisor` after the application's Ecto repo and `Phoenix.PubSub` process.
528536

529537
## Configuration
530538

@@ -720,78 +728,6 @@ FunWithFlags is instrumented with [Telemetry](https://hex.pm/packages/telemetry)
720728

721729
The full list of events emitted by FunWithFlags are documented in the [FunWithFlags.Telemetry](https://hexdocs.pm/fun_with_flags/FunWithFlags.Telemetry.html) module.
722730

723-
## Application Start Behaviour
724-
725-
As explained in the [Installation](#installation) section, above in this document, the `:fun_with_flags` application will start automatically when you add the package as a dependency in your Mixfile. The `:fun_with_flags` application starts its own supervision tree which manages all required processes and is provided by the `FunWithFlags.Supervisor` module.
726-
727-
Sometimes, this can cause issues and race conditions if FunWithFlags is configured to rely on Erlang processes that are owned by another application. For example, if you have configured the `Phoenix.PubSub` cache-busting notification adapter, one of FunWithFlag's processes will immediately try to subscribe to its notifications channel using the provided PubSub process identifier. If that process is not available, FunWithFlags will retry a few times and then give up and raise an exception. This will become a problem if you're using FunWithFlags in a large application (e.g. a Phoenix app) and the `:fun_with_flags` application starts much faster than the Phoenix supervision tree.
728-
729-
In these cases, it's better to directly control how FunWithFlags starts its processes.
730-
731-
The first step is to add the `FunWithFlags.Supervisor` module directly to the supervision tree of the host application. For example, in a Phoenix app it would look like this:
732-
733-
```diff
734-
defmodule MyPhoenixApp.Application do
735-
@moduledoc false
736-
use Application
737-
738-
def start(_type, _args) do
739-
children = [
740-
MyPhoenixApp.Repo,
741-
MyPhoenixAppWeb.Telemetry,
742-
{Phoenix.PubSub, name: MyPhoenixApp.PubSub},
743-
MyPhoenixAppWeb.Endpoint,
744-
+ FunWithFlags.Supervisor,
745-
]
746-
747-
opts = [strategy: :one_for_one, name: MyPhoenixApp.Supervisor]
748-
Supervisor.start_link(children, opts)
749-
end
750-
751-
# ...
752-
```
753-
754-
Then it's necessary to configure the Mix project to not start the `:fun_with_flags` application automatically. This can be accomplished in the Mixfile in a number of ways, for example: (**Note**: These are alternative solutions, you don't need to do both. You must decide which is more appropriate for your setup.)
755-
756-
* **Option A**: Declare the `:fun_with_flags` dependency with either the `runtime: false` or `app: false` options. ([docs](https://hexdocs.pm/mix/1.11.3/Mix.Tasks.Deps.html#module-dependency-definition-options))
757-
758-
```diff
759-
- {:fun_with_flags, "~> 1.6"},
760-
+ {:fun_with_flags, "~> 1.6", runtime: false},
761-
```
762-
763-
If you use releases then you'll also need to modify the `releases` section in `mix.exs` so that it loads the `fun_with_flags` application explicitly (since `runtime: false` / `app: false` will exclude it from the assembled release).
764-
765-
```diff
766-
def project do
767-
[
768-
app: :my_phoenix_app,
769-
+ releases: [
770-
+ my_phoenix_app: [
771-
+ applications: [
772-
+ fun_with_flags: :load
773-
+ ]
774-
+ ]
775-
]
776-
end
777-
```
778-
779-
* **Option B**: Declare that the `:fun_with_flags` application is managed directly by your host application ([docs](https://hexdocs.pm/mix/1.11.3/Mix.Tasks.Compile.App.html)).
780-
781-
```diff
782-
def application do
783-
[
784-
mod: {MyPhoenixApp.Application, []},
785-
+ included_applications: [:fun_with_flags],
786-
extra_applications: [:logger, :runtime_tools]
787-
]
788-
end
789-
```
790-
791-
The result of those changes is that the `:fun_with_flags` application won't be loaded and started automatically, and therefore the FunWithFlags supervision tree won't risk to be started before the other processes in the host Phoenix application. Rather, the supervision tree will start alongside the other core Phoenix processes.
792-
793-
One final note on this topic is that if you're also using [`FunWithFlags.UI`](https://github.com/tompave/fun_with_flags_ui) (refer to the [Web Dashboard](#web-dashboard) section, above in this document), then that will need to be configured as well. The reason is that `:fun_with_flags` is a dependency of `:fun_with_flags_ui`, so including the latter as a dependency will cause the former to be auto-started despite the configuration described above. To avoid this, the same configuration should be used for the `:fun_with_flags_ui` dependency, regardless of the approach used (Option A: `runtime: false`, `app: false`; or Option B: `included_applications`).
794-
795731

796732
## Testing
797733

lib/fun_with_flags/application.ex

Lines changed: 0 additions & 9 deletions
This file was deleted.

mix.exs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ defmodule FunWithFlags.Mixfile do
2323

2424
def application do
2525
# Specify extra applications you'll use from Erlang/Elixir
26-
[extra_applications: extra_applications(Mix.env),
27-
mod: {FunWithFlags.Application, []}]
26+
[extra_applications: extra_applications(Mix.env)]
2827
end
2928

3029
defp extra_applications(:test), do: local_extra_applications()

test/test_helper.exs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ does_anything_need_redis = !(
44
FunWithFlags.Config.persist_in_ecto? && FunWithFlags.Config.phoenix_pubsub?
55
)
66

7-
87
if FunWithFlags.Config.phoenix_pubsub? do
98
# The Phoenix PubSub application must be running before we try to start our
109
# PubSub process and subscribe.
@@ -37,6 +36,9 @@ IO.puts "Notifications adapter: #{inspect(FunWithFlags.Config.notifications_adap
3736
IO.puts "Anything using Redis: #{inspect(does_anything_need_redis)}"
3837
IO.puts "--------------------------------------------------------------"
3938

39+
# Start the FWF Supervision tree.
40+
FunWithFlags.Supervisor.start_link(nil)
41+
4042
if does_anything_need_redis do
4143
FunWithFlags.TestUtils.use_redis_test_db()
4244
end

0 commit comments

Comments
 (0)