Repository navigation
Write a data file update to disk as it arrives, and remove its temporary files when it fails - #178
Draft
jwrosewell wants to merge 6 commits into
Draft
jwrosewell wants to merge 6 commits into
jwrosewell wants to merge 6 commits into
Conversation
reqwest names the URL it requested in its errors, and that URL is the formatted one, whose query carries the licence keys. The service put the error into its own message, so each key reached the error a caller gets and the warning the scheduler logs. The message now takes the error without its URL, with its causes, and names the configured URL.
… cloud request engine does
…iles when it fails The service read the whole response into memory with a single call, which reqwest's blocking client limits to its timeout, 30 seconds by default, then decompressed it into a second buffer. A 2.5 GB download could not finish in 30 seconds on most links, and would have held about 9.7 GB in memory if it had. The body is now read as it arrives into a file beside the data file, with its MD5 taken as it is read, and decompressed into a second file that replaces the data file with a rename. Both files are removed when the update fails, where the old temporary file stayed.
This was referenced Oct 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #160.
Builds on #175, whose commits it carries, because the errors of a download read as it arrives go through the message and redaction that pull request adds. Merge #175 first, and this pull request then shows its own change alone.
Problem
Response::bytes(pipeline-engines/src/data_update_service.rsline 645), which reqwest's blocking client limits, as a whole, to its timeout of 30 seconds by default. A data file update that took longer failed, even while it kept arriving.write_atomically(lines 777 to 782) left its temporary file beside the data file whenever the write or the rename failed.#160 has the details.
Change
Read, so the client's timeout limits each wait for more of it, and written as it arrives to a file beside the data file, with its MD5 taken as it is read. That file is decompressed into a second one beside it, which replaces the data file with a rename. Both are removed when they go out of scope, so an update that fails at any step leaves nothing behind.Readas well.OnPremiseAspectEngine::temp_data_dirno longer says the service uses it, as it never has.How it was verified
New tests:
a_steady_download_longer_than_the_client_timeout_completes(tests/remote_refresh.rs) sends a 51,200 byte file in ten parts over five seconds to a service whose client has a two second timeout.downloading_an_update_holds_little_of_the_file_in_memory(tests/download_memory.rs, alone in its file because it counts every allocation through its own global allocator) applies a 32 MiB update, plain and gzipped, and checks the most memory in use rose by under 8 MiB.a_failed_update_leaves_no_temporary_file(tests/remote_refresh.rs) puts a folder where the data file should be, so the rename fails, and checks nothing else is left.dropping_the_service_stops_a_download_in_progress(tests/remote_refresh.rs) drops the service a second into a scheduled download whose body takes 30 seconds, and checks the drop returns within five seconds and leaves no file behind.Before the change, on a branch holding only the new tests, all four fail:
a_steady_download_longer_than_the_client_timeout_completes:Err("data update failed (StreamError): error reading data update response from 'http://127.0.0.1:51991/datafile': error decoding response body").downloading_an_update_holds_little_of_the_file_in_memory:plain: a 33554432 byte update added 33968136 bytes at most.a_failed_update_leaves_no_temporary_file:["device.dat", "device.tmp-download"]left in the folder.dropping_the_service_stops_a_download_in_progress:dropping the service waited 29.0380915s for the download.After it, all four pass, and the memory test prints
plain: a 33554432 byte update added 473356 bytes at mostandgzip: a 33554432 byte update added 211050 bytes at most.Locally on Windows, with all seven fixes of this sweep merged together (#175, #178, #182, #184, #194, #195 and #196),
cargo test --no-fail-fast -p fiftyone-pipeline-engines -p fiftyone-device-detection-onpremise -p fiftyone-ip-intelligence-onpremise -p fiftyone-device-detection -p fiftyone-ip-intelligence -- --nocapture, with51DEGREES_DD_PATHnaming the Lite Hash file,Enterprise-HashV41.hashbeside it, and51DEGREES_IPI_PATHnaming the ASN file,51Degrees-LiteV41.ipibeside it, gives 130 passed, 0 failed and 2 ignored across 24 test binaries. With the fixes merged,cargo doc --workspace --no-depswithRUSTDOCFLAGS="-D warnings"passes, andrustfmt --checkpasses on every file the seven fixes change.cargo clippy --workspace --all-targets -- -D warningson the merged fixes has not run yet. ThePull Requestworkflow, which builds and tests each pull request on every platform, is waiting for approval to run.Behaviour that changes
.downloador.new, beside the data file, where before one was named with the extensiontmp-download.What remains
InMemorydoes. Rust: On Windows a data update cannot replace the data file of an engine that reads it from disk #167 covers that, with an operational copy of the data file. With this change the failed update leaves no file behind.