akash-akya

akash-akya

Experimenting with running mysql tests in parallel

Hey all,

On my day job, we have a big elixir mono repo and large test suite. Most of our apps uses mysql as database. Given that ecto sandbox does not support async tests for mysql database. Our test suite takes a long time to complete. Basically, the async: true won’t work because of the way mysql transactions work

Approach we are experimenting

We are trying to work around the issue caused by the mysql transaction by using the database itself as an isolation layer. That is, we create multiple databases in the single MySQL instance, having the same structure and configure each connection to connect a different database. For example, if pool_size is 10, we connect each connection to 10 different databases with the same database structure. Since each connection is isolated by database itself instead of transaction, there won’t be deadlock or any such issues.

We wrote a wrapper for ecto.create and ecto.migrate to bring up multiple database for test env. We also made it to run in parallel so that the CI pipeline is fast.

Now we configure a separate database for each connection using configure/1

config :my_app, DummyRepo,
  adapter: Ecto.Adapters.MyXQL,
  ....
  hostname: "localhost",
  port: 3306,
  pool: Ecto.Adapters.SQL.Sandbox,
  pool_size: 10,
  configure: fn args ->
    Keyword.put(args, :database, "dummy_#{args[:pool_index]}") # dummy_1, dummy_2 ... dummy_10
  end

Then we switched our tests to async: true

This is working fine, and we are seeing the speedup we were aiming.

The concern here though is that pool_index is undocumented, and I think it is not meant to be used. But replacing it would be tricky. So I wanted to know if there is any suggestion to handle this better. Perhaps ecto team can help?

Or are you guys following a totally different approach altogether to run MySQL tests in parallel?

First Post!

al2o3cr

al2o3cr

There’s a similar approach baked into mix test, but it’s partitioned at the level of OS processes instead of per-connection. The default configuration generated by Phoenix in config/test.exs appends the partition to the database name:

https://github.com/phoenixframework/phoenix/blob/5408971b36debf7e1b7c88ad7be370726d519a90/installer/lib/phx_new/generator.ex#L340-L347

However, this process-level strategy seems like it only makes sense for splitting tests in a CI-like environment (where each MIX_TEST_PARTITION is a separate node that runs migrations etc) versus running them locally.

Most Liked

akash-akya

akash-akya

I think there are multiple scenarios which can cause deadlock. I don’t remember all details, one such case was where you are trying to insert multiple rows using a column which has unique-index. In innodb inserts in a transaction takes a gap-lock on index value range if the column as uniqueness index.

    Task.async_stream(1..2, fn _ ->
      Repo.transaction(fn ->
        for num <- 9..1 do
          Repo.insert!(%Post{title: "foo_#{num}"}) # :title has unique-index
        end

        Repo.rollback(:ok)
      end)
    end)
    |> Stream.run()

@NobbZ I’m would be happy to share it. But I’m not sure how to package it (perhaps Ecto is the right place for something like this?), and the question about pool_index still remains. I’ll just create draft in GH, let’s see from there.

@joey_the_snake can you expand on this? You mean there will be multiple Ecto.Repo instances connecting to different database with same structure? If so then the code under test dynamically need to choose one of these repo right?

Btw, we only need to do this for test env. So the worst case is it breaks pipeline, and we switch back to old approach.

Last Post!

dimitarvp

dimitarvp

IMO you already handle it well enough.

The only thing I’d change if I had a day to burn on this would likely be to make my own docker-compose.yml file that spins up 20 - 50 separate Elixir containers, each with its own DB, and control them with environment variables (or indeed with MIX_TEST_PARTITION), and see if that accelerates things even further. I doubt it but it could be fun to try because I/O bounded code usually can parallelize super well on something like 5x your CPU threads.

And I wouldn’t worry about using undocumented mechanisms here. Just use that until it’s there and if one version breaks it you can then make a call to either stick to the older version for a while or move to a Docker [Compose] based testing.

If I was in your team I’d simply tell you “good job, you did really well”.

Where Next?

Popular in Discussions Top

CharlesO
Erlang :list.nth simple, but 1 - based nth(1, [H|_]) -&gt; H; nth(N, [_|T]) when N &gt; 1 -&gt; nth(N - 1, T). Elixir Enum.at … coo...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 55125 245
New
pillaiindu
In django there is a cache framework backed by memcached. Rails also puts a lot of emphasis on caching, and even the idea of russian-doll...
New
PragTob
Hello everyone, I know we had quite some threads (read through lots of them) about background job processing but it remains a hotly deba...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
pillaiindu
I want to convert a Phoenix LiveView CRUD website to a CRUD mobile app. What do you think is the easiest way to do so?
New
cvkmohan
The upcoming Phoenix 1.6 release looks very interesting. Became a habit to watch the commits - and - what they are bringing in. phx.gen...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40165 209
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New

We're in Beta

About us Mission Statement