Skip to content
This repository has been archived by the owner on Jan 15, 2025. It is now read-only.

Commit

Permalink
(PE-37481) Add retry with exp backoff on err 32
Browse files Browse the repository at this point in the history
  • Loading branch information
tlehman committed Feb 27, 2024
1 parent c73821a commit fe540a0
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- [Sample Library CMakeLists.txt file](#sample-library-cmakeliststxt-file)
- [Vendoring Other Libraries](#vendoring-other-libraries)
- [How To Release](#how-to-release)
- [How To Run Tests](#how-to-run-tests)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -414,3 +415,16 @@ the `nowide` and `catch` CMake files are both solid examples.
[1]: https://github.com/philsquared/Catch
[2]: https://github.com/miloyip/rapidjson
[3]: json_container/README.md

## How to run tests

To run the leatherman tests, you need `cmake` and a C++ compiler.

```
# at the root of the leatherman/ directory
mkdir build
cd build
cmake ..
make leatherman_test
bin/leatherman_test
```
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ install:
- SET PATH=C:\Ruby21-x64\bin;C:\tools\mingw64\bin;C:\Program Files\gettext-iconv;%PATH%

build_script:
- ps: cmake -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE="C:\tools\pl-build-tools\pl-build-toolchain.cmake" -DCMAKE_INSTALL_PREFIX=C:\tools\leatherman -DBOOST_STATIC=ON -DLEATHERMAN_SHARED="$env:shared" .
- ps: cmake -G "MinGW Makefiles" -DENABLE_CXX_WERROR=OFF -DCMAKE_TOOLCHAIN_FILE="C:\tools\pl-build-tools\pl-build-toolchain.cmake" -DCMAKE_INSTALL_PREFIX=C:\tools\leatherman -DBOOST_STATIC=ON -DLEATHERMAN_SHARED="$env:shared" .
- ps: mingw32-make -j2

test_script:
Expand Down
2 changes: 1 addition & 1 deletion curl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
find_package(Boost 1.54 REQUIRED COMPONENTS regex system filesystem)
find_package(Boost 1.54 REQUIRED COMPONENTS regex system chrono filesystem)

add_leatherman_deps("${Boost_LIBRARIES}")
add_leatherman_includes("${Boost_INCLUDE_DIRS}")
Expand Down
33 changes: 33 additions & 0 deletions curl/src/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
#include <boost/algorithm/string.hpp>
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/fstream.hpp>

#include <boost/chrono.hpp>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <boost/thread/thread.hpp>
#pragma GCC diagnostic pop
#include <sstream>

// Mark string for translation (alias for leatherman::locale::format)
Expand Down Expand Up @@ -128,11 +136,36 @@ namespace leatherman { namespace curl {
return _fp;
}

bool error_file_in_use(const boost::system::error_code& ec) {
bool same = (ec == boost::system::error_code(32, boost::system::system_category()));
LOG_DEBUG("error_file_in_use({1}), same = {2}", ec, same);
return same;
}

// Handle special case where rename fails on windows due to error code 32
void write_retry_with_exp_backoff(boost::filesystem::path const& _temp_path, boost::filesystem::path const& _file_path) {
boost::system::error_code ec;
int max_retries = 5;
int wait_millis = 100;
do {
LOG_DEBUG("Failed rename with error 32, retrying up to {1} more times", max_retries);
boost::this_thread::sleep_for(boost::chrono::milliseconds(wait_millis));
fs::rename(_temp_path, _file_path, ec);
wait_millis *= 2;
max_retries -= 1;
} while (max_retries > 0 && error_file_in_use(ec));
}


void download_temp_file::write() {
LOG_DEBUG("Download completed, now writing result to file {1}", _file_path);
close_fp();
boost::system::error_code ec;
fs::rename(_temp_path, _file_path, ec);
if(error_file_in_use(ec)) {
write_retry_with_exp_backoff(_temp_path, _file_path);
}

if (ec) {
LOG_WARNING("Failed to write the results of the temporary file to the actual file {1}", _file_path);
throw http_file_operation_exception(_req, _file_path, make_file_err_msg(_("failed to move over the temporary file's downloaded contents")));
Expand Down

0 comments on commit fe540a0

Please sign in to comment.