The clients recv will fail with {:error, :closed}, but why? What is Task.await doing to the sockets PID that makes this not work?
Is there a way to asynchronously wait for a single connection on the server side?
The process that accepts the connection becomes the owner of it. When the process dies, which in your example happens immediately after you accept, it will also close the connections it owns.
To solve this problem you can do the sending in the same process as you accept or you can hand over ownership of the connection socket using :gen_tcp.controlling_process/2.
There is an anti-pattern in the sense that the async task is not necessary since the main process is not doing anything while the task is running so you could just as well skip using a task. The only time I would do something like that is if the process is allocating a lot of memory you want quickly garbage collected when it exits.
But if your code is only a snippet from a larger code base where the main process is doing work in the mean time or you spawn multiple tasks then there is nothing wrong with it