[HN Gopher] setBigTimeout
___________________________________________________________________
setBigTimeout
Author : cfj
Score : 198 points
Date : 2024-10-17 18:01 UTC (2 days ago)
(HTM) web link (evanhahn.com)
(TXT) w3m dump (evanhahn.com)
| miiiiiike wrote:
| Got hit with this one a few months ago.
| graypegg wrote:
| Just out of curiosity, what was the use case for a really long
| timeout? Feels like most if not all long timeouts would be best
| served with some sort of "job" you could persist, rather than
| leaving it in the event queue.
| cout wrote:
| https://thedailywtf.com/articles/The_Harbinger_of_the_Epoch_
| graypegg wrote:
| To be fair, this will be fixed by browsers when it's within
| spitting distance of the scale of numbers setTimeout is
| normally used with. (not huge numbers) Like, if it's close
| enough that setTimeout(() => {}, 5000) will stop working a
| month later, that would be a major failure on the browser
| vendor's part. Much too close for comfort.
|
| But I totally understand it not being a priority if the
| situation is: setTimeout(() => {}, 500000000) not working
| in X years.
| BillyTheKing wrote:
| this is the thing with JS and TS - the types and stuff, it's
| all good until you realise that all integers are basically int
| 52 (represented as float 64, with 52 bits for the fraction).
|
| Yes, it's nice and flexible - but also introduces some
| dangerous subtle bugs.
| 8n4vidtmkvmk wrote:
| 2^53-1 I thought.
|
| And no, they're not all that. There's a bunch that are 2^32
| such as this timeout, apparently, plus all the bit shift
| operations.
| vhcr wrote:
| Not ALL integers are 52 bit, BigInts were added on ECMAScript
| 2020.
| sjaak wrote:
| What is the use-case for such a function?
| echoangle wrote:
| Make a joke and have something to write a blogpost about, while
| letting your readers learn something new.
| keithwhor wrote:
| Off the top of my head, a cron scheduler for a server that
| reads from a database and sets a timeout upon boot. Every time
| the server is reboot the timeouts are reinitialized (fail safe
| in case of downtime). If upon boot there's a timeout > 25 days
| it'll get executed immediately which is not the behavior you
| want.
| skykooler wrote:
| Why would you do that in JS rather than just using cron for
| it?
| hinkley wrote:
| This should be an interval with a lookup.
|
| Every five seconds check for due dates sooner than 10 seconds
| from now and schedule them.
|
| The longer a delay the higher the odds the process exits
| without finishing the work.
| bgirard wrote:
| Not having your timeout fire unexpectedly instantly is a good
| use-case IMO.
| yifanl wrote:
| If we're pedantic, this doesn't actually do what's advertised,
| this would be waiting X timeouts worth of event cycles rather
| than just the one for a true Big timeout, assuming the precision
| matters when you're stalling a function for 40 days.
| keithwhor wrote:
| I haven't looked at the code but it's fairly likely the author
| considered this? eg the new timeout is set based on the delta
| of Date.now() instead of just subtracting the time from the
| previous timeout.
| yifanl wrote:
| No, it pretty much just does exactly that.
| const subtractNextDelay = () => { if (typeof
| remainingDelay === "number") { remainingDelay -=
| MAX_REAL_DELAY; } else { remainingDelay
| -= BigInt(MAX_REAL_DELAY); } };
| keithwhor wrote:
| Oh yikes. Yeah; not ideal.
| Aachen wrote:
| To be fair, this is what I expect of any delay function.
| If it needs to be precise to the millisecond,
| _especially_ when scheduled hours or days ahead, I 'd
| default to doing a sleep until shortly before (ballpark:
| 98% of the full time span) and then a smaller sleep for
| the remaining time, or even a busy wait for the last bit
| if it needs to be sub-millisecond accurate
|
| I've had too many sleep functions not work as they should
| to still rely on this, especially on mobile devices and
| webpages where background power consumption is a concern.
| It doesn't excuse new bad implementations but it's also
| not exactly surprising
| keepamovin wrote:
| I guess the dream of programming the next heliopause
| probe in JavaScript is still a ways off hahaha! :)
| sulam wrote:
| But it appears that it is consistent with setTimeout's
| behavior and therefore likely correct in the context it
| will be used.
|
| At least if your definition of "correct" is "does the
| thing most similar to the thing I'm
| extending/replicating". In fact you might believe it's a
| bug to do otherwise, and JS (I'm no expert) doesn't give
| a way to run off the event loop anyway (in all
| implementations). Although I'd be amused to see someone
| running even a 90 day timer in the browser. :)
|
| I've think a very precise timeout would want a different
| name, to distinguish it from setTimeout's behavior.
| gnachman wrote:
| That wouldn't very well because Date.now() isn't monotonic.
| _flux wrote:
| There is a monotonic time source available in JavaScript,
| though: https://developer.mozilla.org/en-
| US/docs/Web/API/Performance...
|
| As I understand it, the precision of such timers has been
| limited a bit in browsers to mitigate some Spectre attacks
| (and maybe others), but I imagine it would still be fine
| for this purpose.
| ballenf wrote:
| Each subtracted timeout is a 25 day timer, so any accumulated
| error would be miniscule. In your example there would a total
| of 2 setTimeouts called, one 25 day timer and one 15 day. I
| think the room for error with this approach is smaller and much
| simpler than calculating the date delta and trying to take into
| account daylight savings, leap days, etc. (but I don't know
| what setTimeout does with those either).
|
| Or maybe I'm missing your point.
| zeroonetwothree wrote:
| You don't need to take into account daylight savings or leap
| days when dealing with unixtime.
| ericyd wrote:
| I don't understand how an implementation detail means it isn't
| doing what is advertised?
| n2d4 wrote:
| The default behaviour of setTimeout seems problematic. Could be
| used for an exploit, because code like this might not work as
| expected: const attackerControlled = ...;
| if (attackerControlled < 60_000) { throw new
| Error("Must wait at least 1min!"); }
| setTimeout(() => { console.log("Surely at least 1min
| has passed!"); }, attackerControlled);
|
| The attacker could set the value to a comically large number and
| the callback would execute immediately. This also seems to be
| true for NaN. The better solution (imo) would be to throw an
| error, but I assume we can't due to backwards compatibility.
| arghwhat wrote:
| A scenario where an attacker can control a timeout where having
| the callback run sooner than one minute later would lead to
| security failures, but having it set to run days later is
| perfectly fine and so no upper bound check is required seems...
| quite a constructed edge case.
|
| The problem here is having an attacker control a security
| sensitive timer in the first place.
| a_cardboard_box wrote:
| The exploit could be a DoS attack. I don't think it's that
| contrived to have a service that runs an expensive operation
| at a fixed rate, controlled by the user, limited to 1
| operation per minute.
| lucideer wrote:
| > _I don 't think it's that contrived to have a service
| that runs an expensive operation at a fixed rate,
| controlled by the user_
|
| Maybe not contrived but definitely insecure by definition.
| Allowing user control of rates is definitely useful & a
| power devs will need to grant but it should never be direct
| control.
| shawnz wrote:
| Can you elaborate on what _indirect_ control would look
| like in your opinion?
|
| No matter how many layers of abstraction you put in
| between, you're still eventually going to be passing a
| value to the setTimeout function that was computed based
| on something the user inputted, right?
|
| If you're not aware of these caveats about extremely high
| timeout values, how do any layers of abstraction in
| between help you prevent this? As far as I can see, the
| only prevention is knowing about the caveats and
| specifically adding validation for them.
| lucideer wrote:
| > _that was computed_
|
| Or comes from a set of known values. This stuff isn't
| that difficult.
|
| This doesn't require prescient knowledge of high timeout
| edge cases. It's generally accepted good security
| practice to limit business logic execution based on user
| input parameters. This goes beyond input validation &
| bounds on user input (both also good practice but most
| likely to just involve a !NaN check here), but more
| broadly user input is data & timeout values are code.
| Data should be treated differently by your app than code.
|
| To generalise the case more, another common case of a
| user submitting a config value that would be used in
| logic would be string labels for categories. You could
| validate against a known list of categories (good but
| potentially expensive) but whether you do or not it's
| still good hygiene to key the user submitted string
| against a category hashmap or enum - this cleanly avoids
| using user input directly in your executing business
| logic.
| bryanrasmussen wrote:
| >Can you elaborate on what indirect control would look
| like in your opinion?
|
| although not the OP this is what I would mean by indirect
| control.
|
| pseudo if userAccountType === "free" then rate = longRate
|
| if userAccountType === "base" then rate = infrequentRate
|
| if userAccountType === "important" then rate =
| frequentRate
|
| obviously rate determination would probably be more
| complicated than just userAccountType
| arghwhat wrote:
| A minimum timing of an individual task is not a useful rate
| limit. I could schedule a bunch of tasks to happen far into
| the future but all at once for example.
|
| Rate limits are implemented with e.g., token buckets which
| fill to a limit at a fixed rate. Timed tasks would then on
| run try to take a token, and if none is present wait for
| one. This would then be dutifully enforced regardless of
| the current state of scheduled tasks.
|
| Only consideration for the timer itself would be to always
| add random jitter to avoid having peak loads coalesce.
| lemagedurage wrote:
| I don't think it's that far fetched that a developer
| implements a rate limiter with setTimeout, where a task
| can only be executed if a timeout is not already running.
| The behaviour in the article is definitely a footgun in
| this scenario.
| chacham15 wrote:
| I would imagine the intent behind this would be that the
| attacker has indirect control over the timeout. E.g. a check
| password input which delays you in between attempts doubling
| the length of time you have to wait in between each failed
| attempt. With this bug in place, the attacker would simply
| wait all the timeouts until the timeout exceeded 25 days at
| which point they could brute force the password check back to
| back.
| arghwhat wrote:
| A login back off should be capped to a number of hours
| rather than be allowed to grow to a month though. I also
| have a hard time seeing this implemented as setTimeouts for
| every failed login attempt instead of storing a last login
| attempt time and counter in a user database with a time
| comparison when login is called.
|
| It's definitely suboptimal though, even if it is
| documented.
| sfvisser wrote:
| Don't ever use attacker controlled data directly in your source
| code without validation. Don't blame setTimeout for this, it's
| impolite!
| n2d4 wrote:
| The problem is the validation. You'd expect you just have to
| validate a lower bound, but you also have to validate an
| upper bound.
| leptons wrote:
| It's user input, you have to validate _all the bounds_ ,
| and filter out whatever else might cause problems. Not
| doing so is a a problem with the programmer, not
| setTimeout.
| swatcoder wrote:
| That's just terrible input validation and has nothing to do
| with setTimeout.
|
| If your code would misbehave outside a certain range of values
| and you're input might span a larger range, _you should be
| checking your input against the range that 's valid_. Your
| sample code simply doesn't do that, and that's why there's a
| bug.
|
| That the bug happens to involve a timer is irrelevant.
| tourist2d wrote:
| > That's just terrible input validation and has nothing to do
| with setTimeout.
|
| Except for the fact that this behaviour is surprising.
|
| > you should be checking your input against the range that's
| valid. Your sample code simply doesn't do that, and that's
| why there's a bug.
|
| Indeed, so why doesn't setTimeout internally do that?
| drdaeman wrote:
| > Indeed, so why doesn't setTimeout internally do that?
|
| Given that `setTimeout` is a part of JavaScript's ancient
| reptilian brain, I wouldn't be surprised it doesn't do
| those checks just because there's some silly compatibility
| requirement still lingering and no one in the committees is
| brave enough to make a breaking change.
|
| (And then, what should setTimeout do if delay is NaN? Do
| nothing? Call immediately? Throw an exception? Personally
| I'd prefer it to throw, but I don't think there's any
| single undeniably correct answer.)
|
| Given the trend to move away from the callbacks, I wonder
| why there is no `async function sleep(delay)` in the
| language, that would be free to sort this out nicely
| without having to be compatible with stuff from '90s. Or
| something like that.
| erinaceousjones wrote:
| I think it's more likely that it's just "undefined
| behaviour" and up to the implementers of the JavaScript
| engines. Given that modern browsers do limit and throttle
| how much you can do with setTimeout in some situations
| (try to use setTimeout on a page after you've switched to
| a VR context! More than like 120hz and it'll just.... Not
| run the timeout anymore, from experience with Chrome).
|
| The browser devs have decided it's acceptable to change
| the behaviour of setTimeout in some situations.
|
| https://developer.chrome.com/blog/timer-throttling-in-
| chrome...
| ashkankiani wrote:
| You are a bad programmer if you think silently doing the
| wrong thing is not a bug. The right thing to do with
| unexpected input as the setTimeout library author is to raise
| an exception.
| log_e wrote:
| It's in the standard library. You're a bad programmer if
| you don't learn the ins and outs of the standard library,
| or make sweeping generalizations.
| notpushkin wrote:
| Standard library is an API just like any other library.
| The only thing different about it is backward
| compatibility (which in JS is paramount and the is reason
| setTimeout can't be fixed directly). It is a bad design
| still.
| balls187 wrote:
| The wrong thing, or the undefined thing?
|
| Feel free to make a proposal to ECMA.
| paulddraper wrote:
| > If your code would misbehave outside a certain range of
| values and you're input might span a larger range, you should
| be checking your input against the range that's valid.
|
| What's funny is you think that about the caller of setTimeout
| but not setTimeout itself :)
| wging wrote:
| In nodejs you at least get a warning along with the problematic
| behavior: Welcome to Node.js v22.7.0.
| Type ".help" for more information. > setTimeout(() =>
| console.log('reached'), 3.456e9) Timeout { <contents
| elided> } > (node:64799) TimeoutOverflowWarning:
| 3456000000 does not fit into a 32-bit signed integer.
| Timeout duration was set to 1. (Use `node --trace-
| warnings ...` to show where the warning was created)
| reached
|
| I'm surprised to see that setTimeout returns an object - I
| assume at one point it was an integer identifying the timer,
| the same way it is on the web. (I think I remember it being so
| at one point.)
| augusto-moura wrote:
| It returns an object for a long time now, I might say it was
| always like this actually. Don't know about very old versions
| dgoldstein0 wrote:
| It's return your differs between node and in a browser. If
| you want to type a variable to hold the return value in
| typescript and share that across node (eg jest tests where
| you might include @types/node) and the browser you need
| ReturnType<typeof setTimeout>, otherwise the code won't
| typecheck in all cases. Similar with setInterval.
| jandrese wrote:
| One could imagine an app that doubles the wait between each
| failed authentication attempt could exploit this by doggedly
| trying until the rate limiter breaks. Maybe not the most
| practical attack, but it is a way this behavior could bite you.
| userbinator wrote:
| I always try to force the timeout to 0 on those really annoying
| download sites that try to make me wait.
|
| Sometimes the wait is over before I find the responsible code,
| and sometimes it does check server-side, but that's just part
| of the fun...
| issafram wrote:
| I wish that I could actually see the code. I understand that it's
| chaining timeouts, but the git site is just garbage
| maxbond wrote:
| You've gotta click "tree".
|
| https://git.sr.ht/~evanhahn/setBigTimeout/tree/main/item/mod...
| zgk7iqea wrote:
| yes, sourcehuts interface is just godawful
| egwynn wrote:
| I agree it's not the prettiest, but I had no trouble clicking
| on "tree" to get to the folder and then "mod.ts" to see the
| code.
| Joker_vD wrote:
| One has still to know that "tree" stands for "source code".
| internetter wrote:
| This is not a sourcehut problem, it is a github problem.
| "Tree" is semantically correct.
| ajkjk wrote:
| What? Of course it's a Sourcehut problem. They chose to
| use that word and could choose to use a better one.
| Klonoar wrote:
| Tree has been used for this kind of thing for decades
| now.
| ajkjk wrote:
| So what? There are still better words for it.
| kelnos wrote:
| That seems like... a normal thing to know?
|
| Pre-GitHub, one of the most popular web git viewers
| (cgit) used "tree" in this way. Never found that to be
| confusing.
|
| (In git, the listing of the files and directories at a
| particular commit is called a "tree". So it's correct.
| Just not as intuitive as you, personally, would like.)
| mort96 wrote:
| Well it doesn't stand for "source code". It's the tree of
| directories and files.
| adregan wrote:
| This reminds me of when I am trying to find something in a
| cabinet, but don't really look very hard, and my wife will say
| "did you even try?" and find it in ~1second.
|
| https://git.sr.ht/~evanhahn/setBigTimeout/tree/main/item/mod...
| Minor49er wrote:
| I clicked on "browse" under the refs: main section and found
| the code right away
| yesco wrote:
| > In most JavaScript runtimes, this duration is represented as a
| 32-bit signed integer
|
| I thought all numbers in JavaScript were basically some variation
| of double precision floating points, if so, why is setTimeout
| limited to a smaller 32bit signed integer?
|
| If this is true, then if I pass something like "0.5", does it
| round the number when casting it to an integer? Or does it
| execute the callback after half a millisecond like you would
| expect it would?
| arp242 wrote:
| You're correct about JS numbers. It works like this presumably
| because the implementation is written in C++ or the like and
| uses an int32 for this, because "25 days ought to be enough for
| everyone".
| drdaeman wrote:
| I thought most non-abandoned C/C++ projects have long
| switched to time_t or similar. 2038 is not that far in the
| future.
| andrewmcwatters wrote:
| 2038 is even "now" if you're calculating futures.
| bobmcnamara wrote:
| Debian conversion should be done mid2025.
| afavour wrote:
| Yes but JS always has backwards compatibility in mind, even
| if it wasn't in the spec. Wouldn't be surprised if more
| modern implementations still add an arbitrary restriction.
| asveikau wrote:
| There's a shocking amount of systems that still have 32 bit
| time_t.
|
| Linux and glibc only started supporting it on 32bit systems
| in the current decade.
| kelnos wrote:
| I mean, we still have 14 years to go. It's not like it's
| 1999 and everyone is freaking out about y2k. We still
| have plenty of time.
|
| That doesn't mean it's fine to wait and leave it until
| the last minute, but we have quite a few last minutes
| left at this point.
| lloeki wrote:
| > we have quite a few last minutes left at this point.
| C'est l'histoire d'un homme qui tombe d'un immeuble de 50
| etages. Le mec, au fur et a mesure de sa
| chute, il se repete sans cesse pour se rassurer:
| "Jusqu'ici tout va bien." "Jusqu'ici tout va
| bien." "Jusqu'ici tout va bien..."
| Mais l'important c'est pas la chute, c'est
| l'atterrissage.
|
| Tx'd: There's this story of a man
| falling off a 50 floor building. Along his fall the guy
| repeats to himself in comfort: "So far, so
| good" "So far, so good" "So far, so
| good..." What matters though is not the
| fall, but the landing.
|
| - Hubert, in La Haine (1995), Mathieu Kassovitz
|
| https://youtube.com/watch?v=U-v6QVlpReU
| blixt wrote:
| JS numbers technically have 53 bits for integers (mantissa) but
| all binary operators turns it into a 32-bit signed integer.
| Maybe this is related somehow to the setTimeout limitation.
| JavaScript also has the >>> unsigned bit shift operator so you
| can squeeze that last bit out of it if you only care about
| positive values: ((2*32-1)>>>0).toString(2).length === 32
| tubs wrote:
| I assume by binary you mean logical? A + b certainly does not
| treat either side as 32bit.
| blixt wrote:
| Sorry, I meant bitwise operators, such as: ~ >> << >>> | &
| DvdGiessen wrote:
| When implementing a tiny timing library in JS a few years back
| I found that most engines indeed seem to cast the value to an
| integer (effectively flooring it), so in order to get
| consistent behaviour in all environments I resorted to always
| calling Math.ceil on the timeout value first [1], thus making
| it so that the callbacks always fire after _at least_ the given
| timeout has passed (same as with regular setTimeout, which also
| cannot guarantee that the engine can run the callback at
| exactly the given timeout due to scheduling). Also used a very
| similar timeout chaining technique as described here, it works
| well!
|
| [1]: https://github.com/DvdGiessen/virtual-
| clock/blob/master/src/...
| darepublic wrote:
| instead of chaining together shorter timeouts, why not calculate
| the datetime of the delay and then invoke via
| window.requestAnimationFrame (by checking the current date ofc).
| augusto-moura wrote:
| Are you suggesting checking the date every frame vs scheduling
| long task every once in a long while? Can't tell if it is
| ironic or not, I'm sorry (damn Poe's law). But assuming not, it
| would be a lot more computationaly expensive to do that,
| timeouts are very optmized and they "give back" on the computer
| resources while in the meantime
| darepublic wrote:
| No irony intended I can be this dumb. Your point did occur to
| me as I posted, was just grasping at straws for a "clean"
| solution
| jw1224 wrote:
| Unlike setTimeout, requestAnimationFrame callbacks are
| automatically skipped if the browser viewport is minimized or
| no longer visible. You wouldn't want to miss the frame that
| matters!
| chii wrote:
| also, not to mention that setBigTimeout would still work in
| serverside js, while requestanimationframe doesn't!
| hiccuphippo wrote:
| So the js engine converting the javascript number (a double?) To
| an int and it's rolling over?
| jackconsidine wrote:
| This type of thing is actually practical. Google Cloud Tasks have
| a max schedule date of 30 days in the future so the typical
| workaround is to chain tasks. As other commenters have suggested
| you can also set a cron check. This has more persistent
| implications on your database, but chaining tasks can fail in
| other ways, or explode if there are retries and a failed request
| does trigger a reschedule (I hate to say I'm speaking from
| experience)
| Waterluvian wrote:
| True. Though if you have a need to trigger something after that
| much time, you might recognize the need to track that scheduled
| event more carefully and want a scheduler. Then you've just got
| a loop checking the clock and your scheduled tasks.
| jackconsidine wrote:
| Right on. Pretty quickly that's the better solution
| keyle wrote:
| This is great for the folks running serverless compute! You get
| to start a process and let it hang until your credit card is
| maxed out. /s
| hmaxdml wrote:
| That was before DBOS -- the serverless platform that bills you
| only for CPU time, not wall clock time ;) see
| https://www.dbos.dev/blog/aws-lambda-hidden-wait-costs
| internetter wrote:
| I don't see how this pricing (or product in general) is any
| better than cloudflare workers.
|
| To be clear, I am not trying to be mean, I'm just curious to
| hear why I would pick this over cf.
| leni536 wrote:
| So... do they not charge for sitting idle and consuming
| memory?
| keepamovin wrote:
| This is excellent. But I was hoping for a setTimeout that
| survived JavaScript environment restarts. Maybe
| _setBigReliableTimeout_ is in your future? Hahaha! :)
| ipython wrote:
| Sounds a lot like the famous windows 95 bug when it would crash
| after 49.7 days of uptime [1]
|
| [1] https://news.ycombinator.com/item?id=28340101
| sehugg wrote:
| GetTickCount() still exists and still returns a DWORD.
| throwaway14356 wrote:
| because no one asked. If you need shorter intervals than the
| minimum you can make a function that calls the other function
| multiple times in a row.
| n_plus_1_acc wrote:
| In response to this, I read the spec of setTimeout, bu I couldn't
| find the part where implementations may have an upper bound. Can
| someone more familiar with the specs point me in the right
| direction?
| zeven7 wrote:
| Adding a comment here to check back later because I'm curious
| now if someone has the answer. I thought it would be easy to
| find the answer, but I can't find it either. I figured it would
| say somewhere a number is converted to an int32, but instead I
| got to the part where there's a map of active timers[1] with
| the time stored as a double[2] without seeing a clear loss
| happening anywhere before that.
|
| [1] https://html.spec.whatwg.org/multipage/timers-and-user-
| promp...
|
| [2] https://w3c.github.io/hr-time/#dom-domhighrestimestamp
| vilius wrote:
| Here's a deep dive in 6 minutes
| https://youtu.be/boD0ReK62FI?si=jSXuQn0DHn3riJgd
|
| Just JS being JS: setTimeout(()=>{}, Infinity) executes
| immediately
| bufferoverflow wrote:
| setTimeout is stranger than you think.
|
| We recently had a failed unit test because setTimeout(fn, 1000)
| triggered at 999ms. That test had ran more than a hundred times
| before just fine. Till one day it didn't.
| jonathanlydall wrote:
| Interesting.
|
| Maybe the system clock did a network time synchronisation
| during the setTimeout window.
| gregoriol wrote:
| I don't think there is any guarantee that setTimeout will run
| at exactly 1000. Though didn't expect it to run earlier, it
| definitely could run later.
| _flux wrote:
| I wonder if your 999ms was measured using wall-clock time or a
| monotonic time source? I imagine a wee time correction at an
| inopportune time could make this happen.
| steve_adams_86 wrote:
| Why does your unit test need to wait one second? Or are you
| controlling the system time, but it still had that error?
| xnorswap wrote:
| setTimeout has no guarantees, and even if it did, your unit
| tests shouldn't depend on it.
|
| Flaky unit tests are a scourge. The top causes of flaky unit
| tests in my experience: - wall clock time (
| and timezones ) - user time ( and timeouts ) -
| network calls - local I/O
|
| These are also, generally speaking, a cause of unnecessarily
| slow unit tests. If your unit test is waiting 1000ms, then it's
| taking 1000ms longer than it needs to.
|
| If you want to test that your component waits, then mock
| setTimeout and verify it's called with 1000 as a parameter.
|
| If you want to test how your component waiting interacts with
| other components, then schedule, without timers, the
| interactions of effects as a separate test.
|
| Fast reliable unit tests are difficult, but a fast reliable
| unit test suite is like having a super-power. It's like driving
| along a windy mountainside road and the difference between one
| with a small gravel trap and one lined with armco barriers.
| Even though in both cases you can the safe driving speed may be
| the same, having the barriers there will give you the
| confidence to actually go at that speed.
|
| Doing every you can to improve the reliably and speed of your
| unit test suite will pay off in developer satisfaction. Every
| time a test suite fails because of a test failing that had
| nothing to do with the changes under test, a bit more of a
| resume gets drafted.
| jffhn wrote:
| >Fast reliable unit tests are difficult
|
| Not difficult if you build your code (not just the test
| suite) around scheduling APIs (and queues implementations,
| etc.) that can be implemented using virtual time instead of
| CPU/wall clock time (I call that soft vs hard time).
|
| Actually I find it a breeze to create such fast and
| deterministic unit tests.
| steve_adams_86 wrote:
| This makes me love having Go handy. I find working with signals
| and time based events so much nicer than other languages I use.
|
| This is fun, though. JS is a bucket of weird little details like
| this.
| oefrha wrote:
| Go timers do have weird little details, in fact one little
| detail changed recently in 1.23 and broke my code. A third
| party dependency selects on sending to a channel and
| time.After(0); before 1.23, due to timer scheduling delay, the
| first case would always win if the channel has capacity to
| receive, but since 1.23 the timer scheduling delay is gone and
| the "timeout" wins half the time. The change is documented at
| https://go.dev/wiki/Go123Timer but unless you read release
| notes very carefully (in fact I don't think the race issue is
| mentioned in 1.23 release notes proper, only on the separate
| deep dive which is not linked from release notes) and are
| intimately familiar with everything that goes into your
| codebase, you can be unexpectedly bitten by change like this
| like me.
| ingen0s wrote:
| You have captured my heart and imagination
| h1fra wrote:
| Keeping a server alive for more than 25days is a feat in this
| serverless world
| alamortsubite wrote:
| The longer the delay, the more likely the process is to crash
| before the timer completes. Use a scheduler instead.
| bhauer wrote:
| Correct take. But I also want to point out that this earnest
| reply is casting "remove curse" on this cursed library.
| purplesyringa wrote:
| Interestingly, this library seems to suffer from the opposite
| problem: where setTimeout can trigger earlier than expected,
| setBigTimeout can trigger never at all!
|
| The problem is that when setBigTimeout is invoked with a
| floating-point number (and numbers are floating-point in JS by
| default), it keeps computing the time left till trigger in
| floating point. But FP numbers are weird: >
| 1e16 - 1 == 1e16 true
|
| At some point, they don't have enough precision to represent
| exact differences, so they start rounding, and this gets
| extremely more inaccurate as the value increases. For correct
| behavior, remainingDelay needs to be stored in BigInt.
|
| Of course, this problem is mostly theoretical, as it starts
| happening at around 2^83 milliseconds, which doesn't even fit in
| a 64-bit time_t, and it's not like humanity will exist by then.
| But still!
| paulddraper wrote:
| I would go so far as to say entirely theoretical.
| rzz3 wrote:
| Awesome! Already have a project I can use this on, thanks.
|
| As a side note, why do you use this weird non-Github, non-Gitlab,
| non-Bitbucket sketchy looking git host? I can see the code
| obviously, but it makes me worry about supply chain security.
| malthejorgensen wrote:
| sourcehut isn't weird at all.
|
| It's made by Drew Devault who is mostly well-respected in the
| hacker community, and it's made exactly to be an alternative to
| BigCo-owned source hosts like GitHub, Gitlab and Bitbucket.
| cchcch wrote:
| Drew isn't well-respected, he's been far too antagonistic to
| far too many people over the years for that.
|
| Latest news is that he authored/published a controversial
| character assassination on Richard Stallman while trying and
| failing to stay anonymous. Then some further digging after
| this unmasking found he's into pedophilic anime. Sitting on
| his compueter uploading drawings of scantily-clad children to
| NSFW subreddits.
|
| No-one with any decency can respect that behavior, it's
| disgusting.
___________________________________________________________________
(page generated 2024-10-19 23:02 UTC)