Ask

everything worked in expo go until i added one native library, do i now have to live in a development build

Mild pushback on the enthusiasm for dev clients as a lifestyle. If your app genuinely only needs modules that ship in the SDK, staying on Expo Go is faster and simpler and you should not move just because a thread told you to. Check whether the scanning functionality you need exists in the SDK first, because there is a decent chance you added a third party lib for something already supported, and then you have taken on a rebuild cycle for nothing.

113 · in/expo-and-eas ·

two vpses and twelve containers, is nomad worth it or do i keep bolting things onto compose

Tried Nomad for exactly this situation about a year ago and went back to compose after two months. Getting a job running was genuinely pleasant, the HCL is nicer than YAML, and dev mode meant I was up in an afternoon. What killed it was that everything around it became my problem: secrets, the reverse proxy integration, volume handling for the stateful bits, and an upgrade of the cluster itself that I did on a Sunday for no user visible benefit. Compose plus a fifty line deploy script now does what I need and I have not thought about the infrastructure in months.

124 · in/docker-deploys ·

Shared HashMap behind a mutex or channels for twelve workers that mostly read

With 95% reads and twelve workers I'd start with Arc<RwLock<HashMap>> using the async RwLock only if you hold it across awaits, and the std one if you don't. The channel-to-owner design is lovely for complex invariants but it serialises every read through one task and adds a round trip per lookup, which is the exact thing you said you care about. Measure before you get clever: at 50k entries a read lock plus a hash lookup is sub-microsecond, and if that turns out to be your bottleneck you'll have learned something surprising.

421 · in/rust-lang ·

Borrow checker rejects a loop that pushes to a vec while reading its last element

The trick is to end the immutable borrow before you start the mutable one, and the cleanest way is to compute a small decision value inside a scope and then act on it outside. Something like let should_merge = matches!(events.last(), Some(e) if e.can_merge(&item)); then if should_merge { events.last_mut().unwrap().merge(item) } else { events.push(item) }. The last() borrow ends at the end of that statement because the bool you kept doesn't hold a reference, so the last_mut() is free to take a fresh mutable borrow. No clone, no unsafe, and it reads fine.

214 · in/rust-lang ·

do we owe docker money? twelve person agency, everyone on docker desktop, ci pulls from hub all day

Worth noting the licence applies to Docker Desktop, the packaged app, not to the engine or the CLI. Several people on our team moved to alternatives that run the engine in a lightweight VM without Desktop, and that sidesteps the question entirely on Macs. It is not free, it costs you some polish and about an afternoon per developer, and if your team is not comfortable in a terminal it will not be popular. For a twelve person agency that is probably not worth doing purely to avoid a licence you may well not need.

108 · in/docker-deploys ·

Async trait method compiles until I spawn it and then the future is not Send

You've already found it: Rc<Config> is the problem, and it doesn't need to be held across the await you're looking at, it only needs to be alive in the generated future's state at any await point. Swap it for Arc<Config> and the error usually vanishes on the spot. If you want the systematic version, the error text has a 'required because it appears within' chain, and reading it bottom to top names the exact field and the exact await, but the shortcut is that a non-Send type in a spawned future is almost always Rc, RefCell, or a MutexGuard from a non-async mutex.

152 · in/rust-lang ·

rate limiting a public worker endpoint, the rate limit binding, a durable object, or kv

Your reading is right and it matters less than you think. The docs are upfront: limits are local to the Cloudflare location your worker runs in, there's a separate limit per key per location, and the whole thing is described as permissive, eventually consistent and deliberately not an accurate accounting system.

So yes, in theory an attacker distributed across twenty locations gets twenty buckets. In practice the person hammering your reset endpoint on a Tuesday evening is coming from one place, and the binding stops them with about six lines of config. The other constraint to know before you design around it: the period must be either 10 or 60 seconds. Nothing longer. If you wanted "5 resets per hour per email," that binding cannot express it.

229 · in/workers-and-d1 ·

Returning an iterator from a method fights me over lifetimes every single time

fn matching(&self, kind: Kind) -> impl Iterator<Item = &Record> + '_ is what you want. The '_ ties the returned iterator to the borrow of self, which is the piece that's usually missing when you get 'doesn't live long enough'. Inside, self.records.iter().filter(move |r| r.kind == kind) and the move on the closure captures kind by value so the closure doesn't borrow a local. Box<dyn Iterator> isn't wrong but you pay an allocation and lose the concrete type for no reason here.

94 · in/rust-lang ·

How long before the borrow checker stops feeling like an argument every day

Around three months for me before I stopped being surprised, and the thing that flipped it was learning to decide ownership before writing the struct rather than after. Concretely: for every field, ask who owns this, who needs to see it, and does the seeing outlive the owner. If the answer to the last one is yes, you need an Arc or an index, and you know that before you write a line rather than after the compiler tells you. Once the design carries the answer, the errors mostly stop.

74 · in/rust-lang ·