I think the answer is clearly NO currently. 1. Being able to run test cases in parallel is a big win already. I assume for most resource-light code bases (like state-less libraries), they can just upgrade to `async: per_test` for all their tests, without worrying about resource utilization.
2. And we can always add more parallelism later (after adding `async: :per_test` support this time) With further optimizations like `max_cases` limit, etc. So, I assume `3.1 spawn_tests/3 before spawn_modules/2` is the way to go now? What do you think? On Monday, September 4, 2023 at 9:08:47 PM UTC+8 José Valim wrote: > The big question is which properties we want to exhibit. > > For example, do we want async tests and async modules to run at the same > time? Or even async tests from different modules together? If the answer is > no, then we can potentially leave parallelism on the table, because we may > be waiting for one test to finish in one module while N other tests from > another module could run. > > If we say yes, the downside is that we could potentially use too many > resources (not CPU wise but stuff like database connections), as in the > worst case scenario we will run M * T processes at once (M = Modules, T = > Tests). We could try to introduce coordination between M * T to adhere to a > limit of max_cases, but that will likely be too complex. > > > On Mon, Sep 4, 2023 at 2:53 PM Yiming Chen <dsds...@gmail.com> wrote: > >> Thanks for confirming and referencing the past discussion! >> >> 100% agree that `async: :per_test | :per_module | true | false` is the >> way to go 👍 >> Most people can then switch to it with a global search & replace. >> >> I looked into the current ExUnit implementation and came up with several >> design directions. >> >> ## Current implementation: >> >> 1. register test modules >> 1. ExUnit.Case calls ExUnit.Server.add_sync_module in after_compile >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/case.ex#L528-L532> >> 2. ExUnit.Server.add_async_module >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/server.ex#L12> >> 2. mix test >> 1. Mix.Tasks.Test >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/mix/lib/mix/tasks/test.ex#L1> >> match test files >> 2. Mix.Compilers.Test.require_and_run/4 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/mix/lib/mix/compilers/test.ex#L25> >> require and run matched test files >> 3. run tests >> 1. ExUnit.run/0 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit.ex#L380> >> 2. ExUnit.Runner.run/2 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L8> >> 3. ExUnit.Runner.async_loop/3 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L95> >> 4. ExUnit.Server.take_async_modules/1 >> 5. ExUnit.Runner.spawn_modules/2 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L154-L165> >> 6. spawn_monitor -> ExUnit.Runner.run_module/2 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L214> >> 7. ExUnit.EventManager >> 1. module_started >> 2. test_started >> 3. test_finished >> 4. module_finished >> 8. ExUnit.Runner.run_module/3 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L278> >> 1. run_setup_all >> 2. spawn_monitor -> module.__ex_unit__(:setup_all, >> test_module.tags) >> 9. ExUnit.Runner.run_tests/3 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L345> >> 10. ExUnit.Runner.run_test/3 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L356> >> 11. ExUnit.Runner.spawn_test/3 >> >> <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L374> >> 1. spawn_test_monitor/4 >> 2. receive_test_reply/4 >> 3. exec_on_exit/3 >> >> ## possible design directions: >> >> 1. registration >> 1. save async test cases separately from async modules >> 2. save async_per_test modules & async_per_module modules >> 2. taking >> 1. return async test cases from >> ExUnit.Server.take_async_per_test_cases/1 >> 2. return async_per_test modules from >> ExUnit.Server.take_async_modules(:per_test, count) >> return async_per_module modules from >> ExUnit.Server.take_async_modules(:per_module, count) >> 3. return both modules from ExUnit.Server.take_async_modules/1 >> 3. running >> 1. spawn_tests/3 before spawn_modules/2 >> 2. spawn_tests/3 inside spawn_modules/2 if it's a per_test async >> module >> >> I'd prefer 1.2 + 2.2 + 3.1: >> >> - save async_per_test modules & async_per_module modules >> - return async_per_test modules from >> ExUnit.Server.take_async_modules(:per_test, count) >> - spawn_tests/3 before spawn_modules/2 >> >> What do you think? >> >> Best, >> Yiming >> >> On Sunday, September 3, 2023 at 10:48:11 PM UTC+8 José Valim wrote: >> >>> Yes, it is desirable and it has come up in the past: >>> https://github.com/elixir-lang/elixir/pull/11949#issuecomment-1177262901 >>> >>> Although I think async: :per_module is what most people want, since the >>> tests in the same module tend to access the same resource, opting-in for it >>> to be per test will be welcome tho. >>> >>> On Thu, Aug 31, 2023 at 4:57 PM Yiming Chen <dsds...@gmail.com> wrote: >>> >>>> Currently, ExUnit's `async: true` option would run test cases in this >>>> module synchronously, >>>> but only run this module asynchronously along with other `async: true` >>>> modules. >>>> >>>> This is to propose we add an option for ExUnit to run asynchronously by >>>> test cases. >>>> >>>> # Background >>>> 1. Async by module was a surprise >>>> >>>> My initial understanding of `async: true` is async by cases, instead of >>>> modules. It's a bit surprising the behavior is later. >>>> >>>> 2. Async by module would behave more like synchronous tests as a module >>>> gets more test cases >>>> >>>> As we grow our libraries/apps, a test module will have more and more >>>> test cases. >>>> It's tedious to break them into separate modules to speed up the test >>>> suite run. >>>> And breaking them into modules has the cost of making related tests >>>> further from each other. >>>> >>>> # Benefits >>>> 1. speed up test suite runs for libraries, apps almost effortlessly >>>> 2. more accurate `async: xxx seconds, sync: yyy seconds` metrics >>>> >>>> # Caveats >>>> >>>> 1. Async by test cases may not run faster than async by modules: >>>> - managing these test cases has a cost on its own >>>> - communicating these test cases between ExUnit Server and Runner >>>> has costs as well >>>> 2. backward compatibility with current `async: true` behavior >>>> >>>> some libs or apps may rely on the async by module behavior. >>>> we should still allow user to use `async: ture` by default, >>>> and make async by test cases an easily opt-in feature. >>>> >>>> 3. Async by test cases may complex the ExUnit implementation even >>>> further >>>> >>>> # Potential solution >>>> >>>> I looked into current ExUnit implementation a little bit >>>> I think `async by test cases` is doable, but I don't have a concrete >>>> solution yet >>>> >>>> A initial idea is to: >>>> 1. instead of saving modules in ExUnit Server, we save test cases (mfa) >>>> in ExUnit Server >>>> 2. when Runner asks for more async tests, ExUnit Server returns test >>>> cases (and also modules) for Runner >>>> >>>> This seems to be a huge change, >>>> so I'd like to know if this feature is desirable/feasible from the core >>>> team's PoV before I dig more into it. >>>> >>>> Best, >>>> Yiming >>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "elixir-lang-core" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to elixir-lang-co...@googlegroups.com. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/elixir-lang-core/51ad9575-71b9-4afe-8996-1dd9e2aea7b8n%40googlegroups.com >>>> >>>> <https://groups.google.com/d/msgid/elixir-lang-core/51ad9575-71b9-4afe-8996-1dd9e2aea7b8n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-co...@googlegroups.com. >> > To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/3ca6d5aa-a073-4144-98c2-0a2d5bcc86f5n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/3ca6d5aa-a073-4144-98c2-0a2d5bcc86f5n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/f25f0f2e-ef18-40a6-8c93-127e3e99c830n%40googlegroups.com.