Where did you learn that import copies the function bodies? I thought it just resolved them at compile time and wrote the fully qualified invocation into the resulting BEAM file.
Oh wait: I just realized you’re not the author of the blog. Sorry!
Where can an Elixir beginner ask for help? – Adolfo Neto – Medium https://buff.ly/2pqzSl6
I have blogged about configuration & Elixir here:
that builds upon some discussions we’ve been having here, most notably:
I think your post also assumes that the build happens on the production or production-like server that also contains the secrets. Am I reading it right?
No, hmm not at all. You can use distillery 2.0 and read them at runtime as I show a the end of post.
Nice! Ya I misread that! Guess I’m so used to there being caveats but ya, Distillery 2.0 with mix config providers is really nice. Thanks for the great post. I might have to redo how I have my app configured now with this in mind. I’m still using the
I think this is where I got tripped up:
Since config providers only execute pre-boot, you must restart the release to pick up configuration changes. If using hot upgrades, the config providers will run during the upgrade, and so will pick up any config changes at that time. https://hexdocs.pm/distillery/extensibility/config_providers.html
So, even though it’s technically read at runtime, it might still feel like compile-time since the app has to reboot to get changed environment variables. (don’t actually have to recompile the app-- just reboot).
Yet this problem is completely addressed in more recent versions. Now you can tell Plug.Parsers how to read the body or tell it to not read it at all in certain cases. The PR was a 2LOC change on each existing parser. No software is perfect, they will all have limitations that need to be addressed. It is amazing what can be achieved when folks approach a weird behaviour as an opportunity to improve things rather than point fingers.
I also want to point out that even a data structure of the request would be bound to “hardly a good example of composa-able”. All that is necessary is for a “middleware” upstream to rewrite a request in a way it is incompatible for downstream. For example, a middleware may discard the request body to save memory (think large file uploads). If another middleware expects the request body to always be there, it will now break. Alternatively you can say it is not possible to discard the request body but then you are opening your application up to easier to pull attack vectors.
So those decisions are not tied to the architectural choice of the project but rather a design decision which could have gone both ways. Plug aims to put stronger emphasis over when the request is read and the response is sent. I would rather read the request body once and make sure to derive all of the properties I need from it in a single place rather than passing the request body around the whole stack in the off chance something else need it.
I had been following the PR and am pleased that it is now fixed.
Never tried to imply I was expecting that, I personally spent quite a long time in Plug source looking for a solution.
I can’t quite believe I’m saying this again, but this is really not my intention.
In functional programming it can be valuable to have as much code as possible pure.
I also recognise that in some cases this goal of purity is not practical.
Plug has made very sensible choices here for it’s model.
However reading and writing a body in plug just is impure in some cases.
My own experiments (Raxx) was never meant to be more than an attempt to see if I could increase the amount of the interface that was pure.
In the end I came up with a solution that I quite like.
I couldn’t quickly google what pull attack vectors are, so I’m not sure what is being said here.
I would just say that Raxx has evolved quite a lot from it’s Rack based inspiration. Arbitrarily large request bodies will not just gut pushed into a data structure .
Hopefully nobody expects software to be perfect. However, when a small and fixable issue is taken as an indicative of a bigger problem, when it is not, the lasting impression is that we don’t have a lot of space for making mistakes (exactly because small mistakes will be taken as an indicative of a bigger problem, when they are not, so we need to make sure everything is fail proof).
Reading and writing a body is always impure. You can’t escape from the real world. The question is how and when you handle it. If you choose to not expose it to your users at all, with a completely pure data driven approach of the request and response with no callbacks, then you are removing runtime capabilities from your users in terms of connection and memory management.
A callback based approach can be made of pure callbacks but the model is still impure and some of the callbacks are likely dictated by the impure nature of the model. For example, in a GenServer you still have
GenServer.reply/2, which is an impure operation, because otherwise certain patterns are impossible to implement.
I am not saying one approach is better than the other. My point is that because the domain modelled here is inherently impure, concessions have to be made at some point (in Erlang/Elixir at least).
Attacks like slowloris are easier to pull off when the body is being kept in memory, especially because the body size limit is typically way higher than the headers one.
I’ve shared 2 short posts on my first Nerves project on the nerves Slack channel and @ConnorRigby reminded me that it could be shared here as well. So here we go:
Being one of Erlang’s most amazing features, hot code reloading is sometimes compared to replacing the wheels on a driving car…
Nice way to put it
This is pretty cool. The rate limiter & circuit breaker use cases is something I didn’t think about before.
Not to take away from this library which looks pretty reasonable on its own, but I don’t think you actually want to do either of those things. In a large enough cluster different servers may have different views of the external service. You don’t want to blow circuits for otherwise healthy nodes just because one unhealthy node says that their circuit is blown. Along with those reasons I would be very hesitant to add that much complexity into the critical path of the request. Rate limiting is much better done by leveraging Little’s Law and increasing or decreasing the number of outbound “connections” dynamically.
Another minor quibble with the post but this statement is inaccurate and I think potentially misleading:
Conflict-resolution is the central feature of CRDTs. In fact, CRDTs are guaranteed to converge globally , meaning that the data will (eventually) be the same at every replica.
CRDTs don’t actually guarantee this. This is a guarantee that the replication protocol has to provide. Even if you assume that there’s a replication protocol underneath your CRDT that manages this correctly it’s only a valid statement if you add the sentence, “as long as there are no network partitions”. The cold hard reality of “eventually consistent systems” (meaning inconsistent systems) is that “eventually” is only theoretical. There’s always a likelihood that your system never converges. Not stating this explicitly has the potential to grossly mislead people.
Elixir (and erlang) are built on processes, which makes concurrency and distribution simpler. What if the processes model extended beyond the server, to the clients of a web application?
GenBrowser enables browsers to send and receive messages like an Elixir process. This simplifies communication and allows the actor model to be applied to reasoning about the whole client-server system.
Hi @keathley, I thought the word “eventually” was enough to cover network partitions, but I’ve adjusted the wording to make it more explicit. I’ve also added some text about anti-entropy algorithms for completeness.
No comment on whether it’s actually a good idea to build some of these things, the goal of this blog post is mostly to get people thinking about different ways they might be able to use the library. Feel free to post in the comments on the blog post itself though.