Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change formatter to attempt to acquire a build lock #391

Closed
wants to merge 2 commits into from

Conversation

mattbaker
Copy link
Contributor

Potential approach to fixing #252. I hate to bring a global lock into the picture again, but I think the strange race conditions with File.cwd are out of our hands since Elixir itself is using the current working directory to find the .formatter.exs configs.

This PR attempts to acquire a build lock as a means of delaying formatting until compilation completes. It makes three retries and Erlang will use a graduated delay between them of 250ms, 500ms, and 1000ms.

I hammered changes as fast as I could (at a rate that was truly unrealistic) and on my project/machine I found this improves things immensely. I only tested on an umbrella project of decent size.

From what I can see this makes things better, even if they're not perfect. It'd be good to see how this behaves for others.

I am by no means tied to this solution, I just wanted to get something out there. I won't be hurt if you close it :)

defp can_format?(file_uri, project_dir) do
file_path = file_uri |> SourceFile.path_from_uri() |> Path.absname()
def try_format(func) do
if Mix.Project.umbrella?() do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not lock non-umbrella also?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. From what I can understand the bug is only happening with umbrella apps. It sounds like the current working directory changes from app to app as compilation occurs. If the cwd is in a different application than the file being formatted there's an error trying to get the formatter.exs.

So I wanted to avoid acquiring a lock if we don't have to, my thinking is the more we do that in the code base the higher the odds of contention when it's time for a new build.

What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error logs indicate that it changes also when compiling deps in regular apps (see #252 (comment), #381 (comment))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see! I missed the deps part, thanks for pointing it out. Sounds like we'll need to do this for all projects then as you suggest.

@mattbaker
Copy link
Contributor Author

I talked with @benwilson512 about projects with long recompilation* times, where this would just end up failing for different reasons (it'd time out). I'm not so sure about this approach anymore.

As I see it:

  • Currently umbrella apps fail to format some of the time.
  • I suspect non-umbrella apps rarely fail. It's true that this can happen in non-umbrella apps per @lukaszsamson's point above, but I think most people aren't recompiling dependencies very often, so it feels like an edge case.

If that's true, then:

  • In projects with recompilation times that average < 1.5s (roughly the time we wait for a lock), this fix makes things fail less often.
  • In umbrella apps with longer average recompilation times, this will fail the same or more often (trading wrong-working-directory errors for failed-to-acquire-lock errors)
  • In non-umbrella apps with longer average recompilation times, this will fail more often (it'll fail to acquire a lock in time)

I think the real answer is to invest in diving deep into Mix.Tasks.Format to see if we can achieve the same thing it does with respect to getting proper formatting options without considering the current working directory. If we can, we'll bypass all this nonsense altogether.

I'm going to close for now. We can always return to this as an option but I'm hoping we won't need it.


* When I say "recompilation time" I'm thinking of the time it takes, on average, to recompile the project after changing a single file.

@mattbaker mattbaker closed this Oct 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants