backoff-0.4.0/.cargo_vcs_info.json0000644000000001120000000000000124210ustar { "git": { "sha1": "08f4e2111ea4b856b24556555d5c6ecf14cfa69d" } } backoff-0.4.0/.github/workflows/check_pr.yml000064400000000000000000000024130000000000000170730ustar 00000000000000# Based on https://github.com/actions-rs/meta/blob/master/recipes/quickstart.md on: [push, pull_request] name: Check PR jobs: check: name: Check runs-on: ubuntu-latest strategy: matrix: feature: - async-std - futures - tokio - wasm-bindgen steps: - name: Checkout sources uses: actions/checkout@v2 - name: Install stable toolchain uses: actions-rs/toolchain@88dc2356392166efad76775c878094f4e83ff746 with: profile: minimal toolchain: stable override: true - name: Run cargo check run: cargo check --features=${{ matrix.feature }} - name: Run cargo test run: cargo test --features=${{ matrix.feature }} lints: name: Lints runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v2 - name: Install stable toolchain uses: actions-rs/toolchain@88dc2356392166efad76775c878094f4e83ff746 with: profile: minimal toolchain: stable override: true components: rustfmt, clippy - name: Run cargo fmt run: cargo fmt --all -- --check - name: Run cargo clippy run: cargo clippy -- -D warningsbackoff-0.4.0/.gitignore000064400000000000000000000000430000000000000131620ustar 00000000000000target/ **/*.rs.bk Cargo.lock .ideabackoff-0.4.0/Cargo.lock0000644000001014150000000000000104040ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "async-attributes" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", "syn", ] [[package]] name = "async-channel" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9" dependencies = [ "concurrent-queue", "event-listener", "futures-core", ] [[package]] name = "async-executor" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", "once_cell", "vec-arena", ] [[package]] name = "async-global-executor" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" dependencies = [ "async-channel", "async-executor", "async-io", "async-mutex", "blocking", "futures-lite", "num_cpus", "once_cell", ] [[package]] name = "async-io" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" dependencies = [ "concurrent-queue", "fastrand", "futures-lite", "libc", "log", "nb-connect", "once_cell", "parking", "polling", "vec-arena", "waker-fn", "winapi", ] [[package]] name = "async-lock" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" dependencies = [ "event-listener", ] [[package]] name = "async-mutex" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" dependencies = [ "event-listener", ] [[package]] name = "async-std" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" dependencies = [ "async-attributes", "async-channel", "async-global-executor", "async-io", "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite", "gloo-timers", "kv-log-macro", "log", "memchr", "num_cpus", "once_cell", "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", ] [[package]] name = "async-task" version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "atomic-waker" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backoff" version = "0.4.0" dependencies = [ "async-std", "futures-core", "futures-executor", "getrandom", "instant", "pin-project-lite", "rand", "reqwest", "tokio", ] [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blocking" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" dependencies = [ "async-channel", "async-task", "atomic-waker", "fastrand", "futures-lite", "once_cell", ] [[package]] name = "bumpalo" version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" [[package]] name = "bytes" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] name = "cache-padded" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] name = "cc" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "concurrent-queue" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" dependencies = [ "cache-padded", ] [[package]] name = "core-foundation" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" [[package]] name = "crossbeam-utils" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg", "cfg-if 1.0.0", "lazy_static", ] [[package]] name = "ctor" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10bcb9d7dcbf7002aaffbb53eac22906b64cdcc127971dcc387d8eb7c95d5560" dependencies = [ "quote", "syn", ] [[package]] name = "encoding_rs" version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "801bbab217d7f79c0062f4f7205b5d4427c6d1a7bd7aafdd1475f7c59d62b283" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "event-listener" version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "fastrand" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" dependencies = [ "instant", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" dependencies = [ "matches", "percent-encoding", ] [[package]] name = "futures-channel" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" dependencies = [ "futures-core", ] [[package]] name = "futures-core" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" [[package]] name = "futures-executor" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" [[package]] name = "futures-lite" version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" dependencies = [ "fastrand", "futures-core", "futures-io", "memchr", "parking", "pin-project-lite", "waker-fn", ] [[package]] name = "futures-sink" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" [[package]] name = "futures-task" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" dependencies = [ "once_cell", ] [[package]] name = "futures-util" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" dependencies = [ "futures-core", "futures-io", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "getrandom" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if 1.0.0", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[package]] name = "gloo-timers" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "h2" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", "http", "indexmap", "slab", "tokio", "tokio-util", "tracing", "tracing-futures", ] [[package]] name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" [[package]] name = "hermit-abi" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "http" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "http-body" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" dependencies = [ "bytes", "http", ] [[package]] name = "httparse" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" [[package]] name = "httpdate" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" [[package]] name = "hyper" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project 1.0.4", "socket2", "tokio", "tower-service", "tracing", "want", ] [[package]] name = "hyper-tls" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", "hyper", "native-tls", "tokio", "tokio-native-tls", ] [[package]] name = "idna" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ "matches", "unicode-bidi", "unicode-normalization", ] [[package]] name = "indexmap" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" dependencies = [ "autocfg", "hashbrown", ] [[package]] name = "instant" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "ipnet" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" dependencies = [ "wasm-bindgen", ] [[package]] name = "kv-log-macro" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ "log", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff" [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if 1.0.0", "value-bag", ] [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "mime" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "mio" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" dependencies = [ "libc", "log", "miow", "ntapi", "winapi", ] [[package]] name = "miow" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ "socket2", "winapi", ] [[package]] name = "native-tls" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" dependencies = [ "lazy_static", "libc", "log", "openssl", "openssl-probe", "openssl-sys", "schannel", "security-framework", "security-framework-sys", "tempfile", ] [[package]] name = "nb-connect" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998" dependencies = [ "libc", "winapi", ] [[package]] name = "ntapi" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ "winapi", ] [[package]] name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" [[package]] name = "openssl" version = "0.10.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" dependencies = [ "bitflags", "cfg-if 1.0.0", "foreign-types", "lazy_static", "libc", "openssl-sys", ] [[package]] name = "openssl-probe" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" version = "0.9.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" dependencies = [ "autocfg", "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "parking" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" dependencies = [ "pin-project-internal 0.4.27", ] [[package]] name = "pin-project" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" dependencies = [ "pin-project-internal 1.0.4", ] [[package]] name = "pin-project-internal" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "pin-project-internal" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "pin-project-lite" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "polling" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" dependencies = [ "cfg-if 0.1.10", "libc", "log", "wepoll-sys", "winapi", ] [[package]] name = "ppv-lite86" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", "rand_chacha", "rand_core", "rand_hc", ] [[package]] name = "rand_chacha" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" dependencies = [ "bitflags", ] [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "reqwest" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd281b1030aa675fb90aa994d07187645bb3c8fc756ca766e7c3070b439de9de" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", "futures-util", "http", "http-body", "hyper", "hyper-tls", "ipnet", "js-sys", "lazy_static", "log", "mime", "native-tls", "percent-encoding", "pin-project-lite", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "winreg", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schannel" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ "lazy_static", "winapi", ] [[package]] name = "security-framework" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" dependencies = [ "bitflags", "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "serde" version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" [[package]] name = "serde_json" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_urlencoded" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", "itoa", "ryu", "serde", ] [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "socket2" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ "cfg-if 1.0.0", "libc", "winapi", ] [[package]] name = "syn" version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", "rand", "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "tinyvec" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6714d663090b6b0acb0fa85841c6d66233d150cdb2602c8f9b8abb03370beb3f" dependencies = [ "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", "pin-project-lite", "tokio-macros", ] [[package]] name = "tokio-macros" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tokio-native-tls" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ "native-tls", "tokio", ] [[package]] name = "tokio-util" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b" dependencies = [ "bytes", "futures-core", "futures-sink", "log", "pin-project-lite", "tokio", ] [[package]] name = "tower-service" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" dependencies = [ "lazy_static", ] [[package]] name = "tracing-futures" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" dependencies = [ "pin-project 0.4.27", "tracing", ] [[package]] name = "try-lock" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" dependencies = [ "matches", ] [[package]] name = "unicode-normalization" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" dependencies = [ "tinyvec", ] [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "url" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" dependencies = [ "form_urlencoded", "idna", "matches", "percent-encoding", ] [[package]] name = "value-bag" version = "1.0.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" dependencies = [ "ctor", ] [[package]] name = "vcpkg" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "vec-arena" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" [[package]] name = "waker-fn" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "want" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ "log", "try-lock", ] [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" dependencies = [ "cfg-if 1.0.0", "serde", "serde_json", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" dependencies = [ "bumpalo", "lazy_static", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94" dependencies = [ "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" [[package]] name = "web-sys" version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "wepoll-sys" version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" dependencies = [ "cc", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winreg" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ "winapi", ] backoff-0.4.0/Cargo.toml0000644000000041660000000000000104340ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "backoff" version = "0.4.0" authors = ["Tibor Benke "] description = "Retry operations with exponential backoff policy.\n" homepage = "https://github.com/ihrwein/backoff" documentation = "https://docs.rs/backoff" readme = "README.md" categories = ["network-programming"] license = "MIT/Apache-2.0" repository = "https://github.com/ihrwein/backoff" [package.metadata.docs.rs] features = ["tokio"] rustdoc-args = ["--cfg", "docsrs"] [[example]] name = "async" required-features = ["tokio"] [[example]] name = "permanent_error" [[example]] name = "retry" [dependencies.async_std_1] version = "1.9" optional = true package = "async-std" [dependencies.futures-core] version = "0.3.8" optional = true default-features = false [dependencies.getrandom] version = "0.2" [dependencies.instant] version = "0.1" [dependencies.pin-project-lite] version = "0.2.7" optional = true [dependencies.rand] version = "0.8" [dependencies.tokio_1] version = "1.0" features = ["time"] optional = true package = "tokio" [dev-dependencies.async_std_1] version = "1.6" features = ["attributes"] package = "async-std" [dev-dependencies.futures-executor] version = "0.3" [dev-dependencies.reqwest] version = "0.11" features = ["json", "blocking"] [dev-dependencies.tokio_1] version = "1.0" features = ["macros", "time", "rt-multi-thread"] package = "tokio" [features] async-std = ["futures", "async_std_1"] default = [] futures = ["futures-core", "pin-project-lite"] tokio = ["futures", "tokio_1"] wasm-bindgen = ["instant/wasm-bindgen", "getrandom/js"] [badges.travis-ci] repository = "ihrwein/backoff" backoff-0.4.0/Cargo.toml.orig000064400000000000000000000027620000000000000140730ustar 00000000000000[package] name = "backoff" version = "0.4.0" edition = "2018" authors = ["Tibor Benke "] license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/ihrwein/backoff" homepage = "https://github.com/ihrwein/backoff" documentation = "https://docs.rs/backoff" categories = ["network-programming"] description = """ Retry operations with exponential backoff policy. """ [badges] travis-ci = { repository = "ihrwein/backoff" } [dependencies] async_std_1 = { package = "async-std", version = "1.9", optional = true } futures-core = { version = "0.3.8", default-features = false, optional = true } instant = "0.1" pin-project-lite = { version = "0.2.7", optional = true } rand = "0.8" getrandom = "0.2" tokio_1 = { package = "tokio", version = "1.0", features = ["time"], optional = true } [dev-dependencies] async_std_1 = { package = "async-std", version = "1.6", features = ["attributes"] } reqwest = { version = "0.11", features = ["json", "blocking"] } tokio_1 = { package = "tokio", version = "1.0", features = ["macros", "time", "rt-multi-thread"] } futures-executor = "0.3" [features] default = [] wasm-bindgen = ["instant/wasm-bindgen", "getrandom/js"] futures = ["futures-core", "pin-project-lite"] tokio = ["futures", "tokio_1"] async-std = ["futures", "async_std_1"] [[example]] name = "async" required-features = ["tokio"] [[example]] name = "permanent_error" [[example]] name = "retry" [package.metadata.docs.rs] features = ["tokio"] rustdoc-args = ["--cfg", "docsrs"] backoff-0.4.0/LICENSE-APACHE000064400000000000000000000251370000000000000131310ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. backoff-0.4.0/LICENSE-MIT000064400000000000000000000020630000000000000126320ustar 00000000000000Copyright (c) 2016 Tibor Benke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. backoff-0.4.0/README.md000064400000000000000000000065560000000000000124700ustar 00000000000000# backoff Exponential backoff and retry. Inspired by the retry mechanism in Google's [google-http-java-client](https://github.com/google/google-http-java-client) library and its [Golang port](https://github.com/cenkalti/backoff). [![Build Status](https://travis-ci.org/ihrwein/backoff.svg?branch=master)](https://travis-ci.org/ihrwein/backoff) [![crates.io](http://meritbadge.herokuapp.com/backoff)](https://crates.io/crates/backoff) [![Documentation](https://docs.rs/backoff/badge.svg)](https://docs.rs/backoff) Compile with feature `wasm-bindgen` or `stdweb` for use in WASM environments. `retry_notify` is not yet supported, as it uses `std::thread::sleep`. :warning: **BREAKING CHANGES**: migration instructions under [Breaking changes](#breaking-changes). ## Overview `backoff` is small crate which allows you to retry operations according to backoff policies. It provides: - Error type to wrap errors as either transient of permanent, - different backoff algorithms, including exponential, - supporting both sync and async code. ## Sync example Just wrap your fallible operation into a closure, and pass it into `retry`: ```rust use backoff::{retry, ExponentialBackoff, Error}; let op = || { reqwest::blocking::get("http://example.com").map_err(Error::transient) }; let _ = retry(&mut ExponentialBackoff::default(), op); ``` The retry policy will use jitters according to the `randomization_factor` field of `ExponentialBackoff`. Check the documentation for more parameters. ## Async example Futures are supported by the `futures` module: ```rust use backoff::ExponentialBackoff; use backoff::future::retry; async fn fetch_url(url: &str) -> Result { retry(ExponentialBackoff::default(), || async { println!("Fetching {}", url); Ok(reqwest::get(url).await?.text().await?) }) .await } ``` ## Breaking changes ### 0.3.x -> 0.4.x #### Adding new field to Error::Transient `Transient` errors got a second field. Useful for handling ratelimits like a HTTP 429 response. To fix broken code, just replace calls of `Error::Transient()` with `Error::transient()`. ### 0.2.x -> 0.3.x #### Removal of Operation trait https://github.com/ihrwein/backoff/pull/28 The `Operation` trait has been removed, please use normal closures implementing `FnMut` instead. The `retry` and `retry_notify` methods were converted to free functions, available in the crate's root. [Example](examples/retry.rs). #### Removal of FutureOperation trait https://github.com/ihrwein/backoff/pull/28 The `FutureOperation` trait has been removed. The `retry` and `retry_notify` methods were converted to free functions, available in the crate's root. [Example](examples/async.rs). #### Changes in feature flags - `stdweb` flag was removed, as the project is abandoned. #### `retry`, `retry_notify` taking ownership of Backoff instances (previously &mut) [Example](examples/retry.rs). ## License Licensed under either of - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the Work by You, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. backoff-0.4.0/examples/async.rs000064400000000000000000000010170000000000000144750ustar 00000000000000extern crate tokio_1 as tokio; use backoff::future::retry; use backoff::ExponentialBackoff; async fn fetch_url(url: &str) -> Result { retry(ExponentialBackoff::default(), || async { println!("Fetching {}", url); Ok(reqwest::get(url).await?.text().await?) }) .await } #[tokio::main] async fn main() { match fetch_url("https://www.rust-lang.org").await { Ok(_) => println!("Successfully fetched"), Err(err) => panic!("Failed to fetch: {}", err), } } backoff-0.4.0/examples/permanent_error.rs000064400000000000000000000022170000000000000165650ustar 00000000000000use backoff::{Error, ExponentialBackoff}; use reqwest::Url; use std::fmt::Display; use std::io::{self, Read}; fn new_io_err(err: E) -> io::Error { io::Error::new(io::ErrorKind::Other, err.to_string()) } fn fetch_url(url: &str) -> Result> { let op = || { println!("Fetching {}", url); let url = Url::parse(url) .map_err(new_io_err) // Permanent errors need to be explicitly constructed. .map_err(Error::Permanent)?; let mut resp = reqwest::blocking::get(url) // Transient errors can be constructed with the ? operator // or with the try! macro. No explicit conversion needed // from E: Error to backoff::Error; .map_err(new_io_err)?; let mut content = String::new(); let _ = resp.read_to_string(&mut content); Ok(content) }; let backoff = ExponentialBackoff::default(); backoff::retry(backoff, op) } fn main() { match fetch_url("https::///wrong URL") { Ok(_) => println!("Successfully fetched"), Err(err) => panic!("Failed to fetch: {}", err), } } backoff-0.4.0/examples/retry.rs000064400000000000000000000011540000000000000145270ustar 00000000000000use backoff::{retry, Error, ExponentialBackoff}; use std::io::Read; fn fetch_url(url: &str) -> Result> { let op = || { println!("Fetching {}", url); let mut resp = reqwest::blocking::get(url)?; let mut content = String::new(); let _ = resp.read_to_string(&mut content); Ok(content) }; let backoff = ExponentialBackoff::default(); retry(backoff, op) } fn main() { match fetch_url("https://www.rust-lang.org") { Ok(_) => println!("Successfully fetched"), Err(err) => panic!("Failed to fetch: {}", err), } } backoff-0.4.0/src/backoff.rs000064400000000000000000000027200000000000000137260ustar 00000000000000use std::time::Duration; /// `Backoff` is a backoff policy for retrying an operation. pub trait Backoff { /// Resets the internal state to the initial value. fn reset(&mut self) {} /// next_backoff() time is elapsed before it is called again. /// If it returns None, it means the operation timed out and no /// further retries are done. fn next_backoff(&mut self) -> Option; } impl Backoff for Box { fn next_backoff(&mut self) -> Option { let this: &mut B = self; this.next_backoff() } fn reset(&mut self) { let this: &mut B = self; this.reset() } } /// Immediately retry the operation. #[derive(Debug)] pub struct Zero {} impl Backoff for Zero { fn next_backoff(&mut self) -> Option { Some(Duration::default()) } } /// The operation should never be retried. #[derive(Debug)] pub struct Stop {} impl Backoff for Stop { fn next_backoff(&mut self) -> Option { None } } /// Contant is a backoff policy which always returns /// a constant duration. #[derive(Debug)] pub struct Constant { interval: Duration, } impl Constant { /// Creates a new Constant backoff with `interval` contant /// backoff. pub fn new(interval: Duration) -> Constant { Constant { interval } } } impl Backoff for Constant { fn next_backoff(&mut self) -> Option { Some(self.interval) } } backoff-0.4.0/src/clock.rs000064400000000000000000000005720000000000000134310ustar 00000000000000use instant::Instant; /// Clock returns the current time. pub trait Clock { fn now(&self) -> Instant; } /// `SystemClock` uses the system's clock to get the current time. /// This Clock should be used for real use-cases. #[derive(Debug, Default, Clone)] pub struct SystemClock {} impl Clock for SystemClock { fn now(&self) -> Instant { Instant::now() } } backoff-0.4.0/src/default.rs000064400000000000000000000012560000000000000137620ustar 00000000000000//! Constants for the exponential backoff policy. /// The default initial interval value in milliseconds (0.5 seconds). pub const INITIAL_INTERVAL_MILLIS: u64 = 500; /// The default randomization factor (0.5 which results in a random period ranging between 50% /// below and 50% above the retry interval). pub const RANDOMIZATION_FACTOR: f64 = 0.5; /// The default multiplier value (1.5 which is 50% increase per back off). pub const MULTIPLIER: f64 = 1.5; /// The default maximum back off time in milliseconds (1 minute). pub const MAX_INTERVAL_MILLIS: u64 = 60_000; /// The default maximum elapsed time in milliseconds (15 minutes). pub const MAX_ELAPSED_TIME_MILLIS: u64 = 900_000; backoff-0.4.0/src/error.rs000064400000000000000000000104750000000000000134720ustar 00000000000000use std::error; use std::fmt; use instant::Duration; /// Error is the error value in an operation's /// result. /// /// Based on the two possible values, the operation /// may be retried. pub enum Error { /// Permanent means that it's impossible to execute the operation /// successfully. This error is immediately returned from `retry()`. Permanent(E), /// Transient means that the error is temporary. If the `retry_after` is `None` /// the operation should be retried according to the backoff policy, else after /// the specified duration. Useful for handling ratelimits like a HTTP 429 response. Transient { err: E, retry_after: Option, }, } impl Error { // Creates an permanent error. pub fn permanent(err: E) -> Self { Error::Permanent(err) } // Creates an transient error which is retried according to the backoff // policy. pub fn transient(err: E) -> Self { Error::Transient { err, retry_after: None, } } /// Creates a transient error which is retried after the specified duration. /// Useful for handling ratelimits like a HTTP 429 response. pub fn retry_after(err: E, duration: Duration) -> Self { Error::Transient { err, retry_after: Some(duration), } } } impl fmt::Display for Error where E: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { Error::Permanent(ref err) | Error::Transient { ref err, retry_after: _, } => err.fmt(f), } } } impl fmt::Debug for Error where E: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { let (name, err) = match *self { Error::Permanent(ref err) => ("Permanent", err as &dyn fmt::Debug), Error::Transient { ref err, retry_after: _, } => ("Transient", err as &dyn fmt::Debug), }; f.debug_tuple(name).field(err).finish() } } impl error::Error for Error where E: error::Error, { fn description(&self) -> &str { match *self { Error::Permanent(_) => "permanent error", Error::Transient { .. } => "transient error", } } fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { Error::Permanent(ref err) | Error::Transient { ref err, retry_after: _, } => err.source(), } } fn cause(&self) -> Option<&dyn error::Error> { self.source() } } /// By default all errors are transient. Permanent errors can /// be constructed explicitly. This implementation is for making /// the question mark operator (?) and the `try!` macro to work. impl From for Error { fn from(err: E) -> Error { Error::Transient { err, retry_after: None, } } } impl PartialEq for Error where E: PartialEq, { fn eq(&self, other: &Self) -> bool { match (self, other) { (Error::Permanent(ref self_err), Error::Permanent(ref other_err)) => { self_err == other_err } ( Error::Transient { err: self_err, retry_after: self_retry_after, }, Error::Transient { err: other_err, retry_after: other_retry_after, }, ) => self_err == other_err && self_retry_after == other_retry_after, _ => false, } } } #[test] fn create_permanent_error() { let e = Error::permanent("err"); assert_eq!(e, Error::Permanent("err")); } #[test] fn create_transient_error() { let e = Error::transient("err"); assert_eq!( e, Error::Transient { err: "err", retry_after: None } ); } #[test] fn create_transient_error_with_retry_after() { let retry_after = Duration::from_secs(42); let e = Error::retry_after("err", retry_after); assert_eq!( e, Error::Transient { err: "err", retry_after: Some(retry_after), } ); } backoff-0.4.0/src/exponential.rs000064400000000000000000000246470000000000000146750ustar 00000000000000use instant::Instant; use std::marker::PhantomData; use std::time::Duration; use crate::backoff::Backoff; use crate::clock::Clock; use crate::default; #[derive(Debug)] pub struct ExponentialBackoff { /// The current retry interval. pub current_interval: Duration, /// The initial retry interval. pub initial_interval: Duration, /// The randomization factor to use for creating a range around the retry interval. /// /// A randomization factor of 0.5 results in a random period ranging between 50% below and 50% /// above the retry interval. pub randomization_factor: f64, /// The value to multiply the current interval with for each retry attempt. pub multiplier: f64, /// The maximum value of the back off period. Once the retry interval reaches this /// value it stops increasing. pub max_interval: Duration, /// The system time. It is calculated when an [`ExponentialBackoff`](struct.ExponentialBackoff.html) instance is /// created and is reset when [`retry`](../trait.Operation.html#method.retry) is called. pub start_time: Instant, /// The maximum elapsed time after instantiating [`ExponentialBackfff`](struct.ExponentialBackoff.html) or calling /// [`reset`](trait.Backoff.html#method.reset) after which [`next_backoff`](../trait.Backoff.html#method.reset) returns `None`. pub max_elapsed_time: Option, /// The clock used to get the current time. pub clock: C, } impl Default for ExponentialBackoff where C: Clock + Default, { fn default() -> ExponentialBackoff { let mut eb = ExponentialBackoff { current_interval: Duration::from_millis(default::INITIAL_INTERVAL_MILLIS), initial_interval: Duration::from_millis(default::INITIAL_INTERVAL_MILLIS), randomization_factor: default::RANDOMIZATION_FACTOR, multiplier: default::MULTIPLIER, max_interval: Duration::from_millis(default::MAX_INTERVAL_MILLIS), max_elapsed_time: Some(Duration::from_millis(default::MAX_ELAPSED_TIME_MILLIS)), clock: C::default(), start_time: Instant::now(), }; eb.reset(); eb } } impl ExponentialBackoff { /// Returns the elapsed time since start_time. pub fn get_elapsed_time(&self) -> Duration { self.clock.now().duration_since(self.start_time) } fn get_random_value_from_interval( randomization_factor: f64, random: f64, current_interval: Duration, ) -> Duration { let current_interval_nanos = duration_to_nanos(current_interval); let delta = randomization_factor * current_interval_nanos; let min_interval = current_interval_nanos - delta; let max_interval = current_interval_nanos + delta; // Get a random value from the range [minInterval, maxInterval]. // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then // we want a 33% chance for selecting either 1, 2 or 3. let diff = max_interval - min_interval; let nanos = min_interval + (random * (diff + 1.0)); nanos_to_duration(nanos) } fn increment_current_interval(&mut self) -> Duration { let current_interval_nanos = duration_to_nanos(self.current_interval); let max_interval_nanos = duration_to_nanos(self.max_interval); // Check for overflow, if overflow is detected set the current interval to the max interval. if current_interval_nanos >= max_interval_nanos / self.multiplier { self.max_interval } else { let nanos = current_interval_nanos * self.multiplier; nanos_to_duration(nanos) } } } fn duration_to_nanos(d: Duration) -> f64 { d.as_secs() as f64 * 1_000_000_000.0 + f64::from(d.subsec_nanos()) } fn nanos_to_duration(nanos: f64) -> Duration { let secs = nanos / 1_000_000_000.0; let nanos = nanos as u64 % 1_000_000_000; Duration::new(secs as u64, nanos as u32) } impl Backoff for ExponentialBackoff where C: Clock, { fn reset(&mut self) { self.current_interval = self.initial_interval; self.start_time = self.clock.now(); } fn next_backoff(&mut self) -> Option { let elapsed_time = self.get_elapsed_time(); match self.max_elapsed_time { Some(v) if elapsed_time > v => None, _ => { let random = rand::random::(); let randomized_interval = Self::get_random_value_from_interval( self.randomization_factor, random, self.current_interval, ); self.current_interval = self.increment_current_interval(); if let Some(max_elapsed_time) = self.max_elapsed_time { if elapsed_time + randomized_interval <= max_elapsed_time { Some(randomized_interval) } else { None } } else { Some(randomized_interval) } } } } } impl Clone for ExponentialBackoff where C: Clone, { fn clone(&self) -> Self { let clock = self.clock.clone(); ExponentialBackoff { clock, ..*self } } } /// Builder for [`ExponentialBackoff`](type.ExponentialBackoff.html). /// /// TODO: Example #[derive(Debug)] pub struct ExponentialBackoffBuilder { initial_interval: Duration, randomization_factor: f64, multiplier: f64, max_interval: Duration, max_elapsed_time: Option, _clock: PhantomData, } impl Default for ExponentialBackoffBuilder { fn default() -> Self { Self { initial_interval: Duration::from_millis(default::INITIAL_INTERVAL_MILLIS), randomization_factor: default::RANDOMIZATION_FACTOR, multiplier: default::MULTIPLIER, max_interval: Duration::from_millis(default::MAX_INTERVAL_MILLIS), max_elapsed_time: Some(Duration::from_millis(default::MAX_ELAPSED_TIME_MILLIS)), _clock: PhantomData, } } } impl ExponentialBackoffBuilder where C: Clock + Default, { pub fn new() -> Self { Default::default() } /// The initial retry interval. pub fn with_initial_interval(&mut self, initial_interval: Duration) -> &mut Self { self.initial_interval = initial_interval; self } /// The randomization factor to use for creating a range around the retry interval. /// /// A randomization factor of 0.5 results in a random period ranging between 50% below and 50% /// above the retry interval. pub fn with_randomization_factor(&mut self, randomization_factor: f64) -> &mut Self { self.randomization_factor = randomization_factor; self } /// The value to multiply the current interval with for each retry attempt. pub fn with_multiplier(&mut self, multiplier: f64) -> &mut Self { self.multiplier = multiplier; self } /// The maximum value of the back off period. Once the retry interval reaches this /// value it stops increasing. pub fn with_max_interval(&mut self, max_interval: Duration) -> &mut Self { self.max_interval = max_interval; self } /// The maximum elapsed time after instantiating [`ExponentialBackfff`](struct.ExponentialBackoff.html) or calling /// [`reset`](trait.Backoff.html#method.reset) after which [`next_backoff`](../trait.Backoff.html#method.reset) returns `None`. pub fn with_max_elapsed_time(&mut self, max_elapsed_time: Option) -> &mut Self { self.max_elapsed_time = max_elapsed_time; self } pub fn build(&self) -> ExponentialBackoff { ExponentialBackoff { current_interval: self.initial_interval, initial_interval: self.initial_interval, randomization_factor: self.randomization_factor, multiplier: self.multiplier, max_interval: self.max_interval, max_elapsed_time: self.max_elapsed_time, clock: C::default(), start_time: Instant::now(), } } } #[cfg(test)] use crate::clock::SystemClock; #[test] fn get_randomized_interval() { // 33% chance of being 1. let f = ExponentialBackoff::::get_random_value_from_interval; assert_eq!(Duration::new(0, 1), f(0.5, 0.0, Duration::new(0, 2))); assert_eq!(Duration::new(0, 1), f(0.5, 0.33, Duration::new(0, 2))); // 33% chance of being 2. assert_eq!(Duration::new(0, 2), f(0.5, 0.34, Duration::new(0, 2))); assert_eq!(Duration::new(0, 2), f(0.5, 0.66, Duration::new(0, 2))); // 33% chance of being 3. assert_eq!(Duration::new(0, 3), f(0.5, 0.67, Duration::new(0, 2))); assert_eq!(Duration::new(0, 3), f(0.5, 0.99, Duration::new(0, 2))); } #[test] fn exponential_backoff_builder() { let initial_interval = Duration::from_secs(1); let max_interval = Duration::from_secs(2); let multiplier = 3.0; let randomization_factor = 4.0; let backoff: ExponentialBackoff = ExponentialBackoffBuilder::new() .with_initial_interval(initial_interval) .with_multiplier(multiplier) .with_randomization_factor(randomization_factor) .with_max_interval(max_interval) .with_max_elapsed_time(None) .build(); assert_eq!(backoff.initial_interval, initial_interval); assert_eq!(backoff.current_interval, initial_interval); assert_eq!(backoff.multiplier, multiplier); assert_eq!(backoff.randomization_factor, randomization_factor); assert_eq!(backoff.max_interval, max_interval); assert_eq!(backoff.max_elapsed_time, None); } #[test] fn exponential_backoff_default_builder() { let backoff: ExponentialBackoff = ExponentialBackoffBuilder::new().build(); assert_eq!( backoff.initial_interval, Duration::from_millis(default::INITIAL_INTERVAL_MILLIS) ); assert_eq!( backoff.current_interval, Duration::from_millis(default::INITIAL_INTERVAL_MILLIS) ); assert_eq!(backoff.multiplier, default::MULTIPLIER); assert_eq!(backoff.randomization_factor, default::RANDOMIZATION_FACTOR); assert_eq!( backoff.max_interval, Duration::from_millis(default::MAX_INTERVAL_MILLIS) ); assert_eq!( backoff.max_elapsed_time, Some(Duration::from_millis(default::MAX_ELAPSED_TIME_MILLIS)) ); } backoff-0.4.0/src/future.rs000064400000000000000000000153020000000000000136450ustar 00000000000000use std::{ future::Future, pin::Pin, task::{Context, Poll}, time::Duration, }; use futures_core::ready; use pin_project_lite::pin_project; use crate::{backoff::Backoff, error::Error}; use crate::retry::{NoopNotify, Notify}; pub trait Sleeper { type Sleep: Future + Send + 'static; fn sleep(&self, dur: Duration) -> Self::Sleep; } /// Retries given `operation` according to the [`Backoff`] policy /// [`Backoff`] is reset before it is used. /// The returned future can be spawned onto a compatible runtime. /// /// Only available through the `tokio` and `async-std` feature flags. /// /// # Example /// /// ```rust /// use backoff::ExponentialBackoff; /// /// async fn f() -> Result<(), backoff::Error<&'static str>> { /// // Business logic... /// Err(backoff::Error::Permanent("error")) /// } /// /// # async fn go() { /// backoff::future::retry(ExponentialBackoff::default(), f).await.err().unwrap(); /// # } /// # fn main() { futures_executor::block_on(go()); } /// ``` #[cfg(any(feature = "tokio", feature = "async-std"))] pub fn retry( backoff: B, operation: Fn, ) -> Retry where B: Backoff, Fn: FnMut() -> Fut, Fut: Future>>, { retry_notify(backoff, operation, NoopNotify) } /// Retries given `operation` according to the [`Backoff`] policy. /// Calls `notify` on failed attempts (in case of [`Error::Transient`]). /// [`Backoff`] is reset before it is used. /// The returned future can be spawned onto a compatible runtime. /// /// Only available through the `tokio` and `async-std` feature flags. /// /// # Async `notify` /// /// `notify` can be neither `async fn` or [`Future`]. If you need to perform some async /// operations inside `notify`, consider using your runtimes task-spawning functionality. /// /// The reason behind this is that [`Retry`] future cannot be responsible for polling /// `notify` future, because can easily be dropped _before_ `notify` is completed. /// So, considering the fact that most of the time no async operations are required in /// `notify`, it's up to the caller to decide how async `notify` should be performed. /// /// # Example /// /// ```rust /// use backoff::backoff::Stop; /// /// async fn f() -> Result<(), backoff::Error<&'static str>> { /// // Business logic... /// Err(backoff::Error::transient("error")) /// } /// /// # async fn go() { /// let err = backoff::future::retry_notify(Stop {}, f, |e, dur| { /// println!("Error happened at {:?}: {}", dur, e) /// }) /// .await /// .err() /// .unwrap(); /// assert_eq!(err, "error"); /// # } /// # fn main() { futures_executor::block_on(go()); } /// ``` #[cfg(any(feature = "tokio", feature = "async-std"))] pub fn retry_notify( mut backoff: B, operation: Fn, notify: N, ) -> Retry where B: Backoff, Fn: FnMut() -> Fut, Fut: Future>>, N: Notify, { backoff.reset(); Retry::new(rt_sleeper(), backoff, notify, operation) } pin_project! { /// Retry implementation. pub struct Retry { // The [`Sleeper`] that we generate the `delay` futures from. sleeper: S, // [`Backoff`] implementation to count next [`Retry::delay`] with. backoff: B, // [`Future`] which delays execution before next [`Retry::operation`] invocation. #[pin] delay: OptionPinned, // Operation to be retried. It must return [`Future`]. operation: Fn, // [`Future`] being resolved once [`Retry::operation`] is completed. #[pin] fut: Fut, // [`Notify`] implementation to track [`Retry`] ticks. notify: N, } } impl Retry where S: Sleeper, Fn: FnMut() -> Fut, Fut: Future>>, { pub fn new(sleeper: S, backoff: B, notify: N, mut operation: Fn) -> Self { let fut = operation(); Retry { sleeper, backoff, delay: OptionPinned::None, operation, fut, notify, } } } pin_project! { #[project = OptionProj] enum OptionPinned { Some { #[pin] inner: T, }, None, } } impl Future for Retry where S: Sleeper, B: Backoff, N: Notify, Fn: FnMut() -> Fut, Fut: Future>>, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.project(); loop { if let OptionProj::Some { inner: delay } = this.delay.as_mut().project() { ready!(delay.poll(cx)); this.delay.set(OptionPinned::None); } match ready!(this.fut.as_mut().poll(cx)) { Ok(v) => return Poll::Ready(Ok(v)), Err(Error::Permanent(e)) => return Poll::Ready(Err(e)), Err(Error::Transient { err, retry_after }) => { match retry_after.or_else(|| this.backoff.next_backoff()) { Some(duration) => { this.notify.notify(err, duration); this.delay.set(OptionPinned::Some { inner: this.sleeper.sleep(duration), }); this.fut.set((this.operation)()); } None => return Poll::Ready(Err(err)), } } } } } } #[cfg(all(feature = "tokio", feature = "async-std"))] compile_error!("Feature \"tokio\" and \"async-std\" cannot be enabled at the same time"); #[cfg(feature = "async-std")] fn rt_sleeper() -> impl Sleeper { AsyncStdSleeper } #[cfg(feature = "tokio")] fn rt_sleeper() -> impl Sleeper { TokioSleeper } #[cfg(feature = "tokio")] #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] struct TokioSleeper; #[cfg(feature = "tokio")] #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] impl Sleeper for TokioSleeper { type Sleep = ::tokio_1::time::Sleep; fn sleep(&self, dur: Duration) -> Self::Sleep { ::tokio_1::time::sleep(dur) } } #[cfg(feature = "async-std")] #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))] struct AsyncStdSleeper; #[cfg(feature = "async-std")] #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))] impl Sleeper for AsyncStdSleeper { type Sleep = Pin + Send + 'static>>; fn sleep(&self, dur: Duration) -> Self::Sleep { Box::pin(::async_std_1::task::sleep(dur)) } } backoff-0.4.0/src/lib.rs000064400000000000000000000175770000000000000131210ustar 00000000000000#![cfg_attr(docsrs, deny(broken_intra_doc_links))] #![cfg_attr(docsrs, feature(doc_cfg))] //! `ExponentialBackoff` is a backoff implementation that increases the backoff //! period for each retry attempt using a randomization function that grows exponentially. //! //! [`next_backoff`]: backoff/trait.Backoff.html#tymethod.next_backoff //! [`reset`]: backoff/trait.Backoff.html#tymethod.reset //! //! [`next_backoff`] is calculated using the following formula: //! //!```text //! randomized interval = //! retry_interval * (random value in range [1 - randomization_factor, 1 + randomization_factor]) //!``` //! //! In other words [`next_backoff`] will range between the randomization factor //! percentage below and above the retry interval. //! //! For example, given the following parameters: //! //!```text //!retry_interval = 2 //!randomization_factor = 0.5 //!multiplier = 2 //!``` //! //! the actual backoff period used in the next retry attempt will range between 1 and 3 seconds, //! multiplied by the exponential, that is, between 2 and 6 seconds. //! //! **Note**: `max_interval` caps the `retry_interval` and not the randomized interval. //! //! If the time elapsed since an [`ExponentialBackoff`](type.ExponentialBackoff.html) instance is created goes past the //! `max_elapsed_time`, then the method [`next_backoff`] starts returning `None`. //! //! The elapsed time can be reset by calling [`reset`]. //! //! Example: Given the following default arguments, for 10 tries the sequence will be, //! and assuming we go over the `max_elapsed_time` on the 10th try: //! //! Request # | `retry_interval` (seconds) | Randomized Interval (seconds) //! -----------|--------------------------|-------------------------------- //! 1 | 0.5 | [0.25, 0.75] //! 2 | 0.75 | [0.375, 1.125] //! 3 | 1.125 | [0.562, 1.687] //! 4 | 1.687 | [0.8435, 2.53] //! 5 | 2.53 | [1.265, 3.795] //! 6 | 3.795 | [1.897, 5.692] //! 7 | 5.692 | [2.846, 8.538] //! 8 | 8.538 | [4.269, 12.807] //! 9 | 12.807 | [6.403, 19.210] //! 10 | 19.210 | None //! //! # Examples //! //! ## Permanent errors //! //! Permanent errors are not retried. You have to wrap your error value explicitly //! into `Error::Permanent`. You can use `Result`'s `map_err` method. //! //! `examples/permanent_error.rs`: //! //! ```rust,no_run //! use backoff::{Error, ExponentialBackoff}; //! use reqwest::Url; //! //! use std::fmt::Display; //! use std::io::{self, Read}; //! //! fn new_io_err(err: E) -> io::Error { //! io::Error::new(io::ErrorKind::Other, err.to_string()) //! } //! //! fn fetch_url(url: &str) -> Result> { //! let op = || { //! println!("Fetching {}", url); //! let url = Url::parse(url) //! .map_err(new_io_err) //! // Permanent errors need to be explicitly constructed. //! .map_err(Error::Permanent)?; //! //! let mut resp = reqwest::blocking::get(url) //! // Transient errors can be constructed with the ? operator //! // or with the try! macro. No explicit conversion needed //! // from E: Error to backoff::Error; //! .map_err(new_io_err)?; //! //! let mut content = String::new(); //! let _ = resp.read_to_string(&mut content); //! Ok(content) //! }; //! //! let backoff = ExponentialBackoff::default(); //! backoff::retry(backoff, op) //! } //! //! fn main() { //! match fetch_url("https::///wrong URL") { //! Ok(_) => println!("Successfully fetched"), //! Err(err) => panic!("Failed to fetch: {}", err), //! } //! } //! ``` //! //! ## Transient errors //! //! Transient errors can be constructed by wrapping your error value into `Error::transient`. //! By using the ? operator or the `try!` macro, you always get transient errors. //! //! You can also construct transient errors that are retried after a given //! interval with `Error::retry_after()` - useful for 429 errors. //! //! `examples/retry.rs`: //! //! ```rust //! use backoff::{retry, Error, ExponentialBackoff}; //! //! use std::io::Read; //! //! fn fetch_url(url: &str) -> Result> { //! let mut op = || { //! println!("Fetching {}", url); //! let mut resp = reqwest::blocking::get(url)?; //! //! let mut content = String::new(); //! let _ = resp.read_to_string(&mut content); //! Ok(content) //! }; //! //! let backoff = ExponentialBackoff::default(); //! retry(backoff, op) //! } //! //! fn main() { //! match fetch_url("https://www.rust-lang.org") { //! Ok(_) => println!("Sucessfully fetched"), //! Err(err) => panic!("Failed to fetch: {}", err), //! } //! } //! ``` //! //! Output with internet connection: //! //! ```text //! $ time cargo run --example retry //! Compiling backoff v0.1.0 (file:///home/tibi/workspace/backoff) //! Finished dev [unoptimized + debuginfo] target(s) in 1.54 secs //! Running `target/debug/examples/retry` //! Fetching https://www.rust-lang.org //! Sucessfully fetched //! //! real 0m2.003s //! user 0m1.536s //! sys 0m0.184s //! ``` //! //! Output without internet connection //! //! ```text //! $ time cargo run --example retry //! Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs //! Running `target/debug/examples/retry` //! Fetching https://www.rust-lang.org //! Fetching https://www.rust-lang.org //! Fetching https://www.rust-lang.org //! Fetching https://www.rust-lang.org //! ^C //! //! real 0m2.826s //! user 0m0.008s //! sys 0m0.000s //! ``` //! //! ### Async //! //! Please set either the `tokio` or `async-std` features in Cargo.toml to enable the async support of this library, i.e.: //! //! ```toml //! backoff = { version = "x.y.z", features = ["tokio"] } //! ``` //! //! A `Future>` can be easily retried: //! //! `examples/async.rs`: //! //! ```rust,no_run,ignore //! //! extern crate tokio_1 as tokio; //! //! use backoff::ExponentialBackoff; //! //! async fn fetch_url(url: &str) -> Result { //! backoff::future::retry(ExponentialBackoff::default(), || async { //! println!("Fetching {}", url); //! Ok(reqwest::get(url).await?.text().await?) //! }) //! .await //! } //! //! #[tokio::main] //! async fn main() { //! match fetch_url("https://www.rust-lang.org").await { //! Ok(_) => println!("Successfully fetched"), //! Err(err) => panic!("Failed to fetch: {}", err), //! } //! } //! ``` //! # Feature flags //! //! - `futures`: enables futures support, //! - `tokio`: enables support for the [tokio](https://crates.io/crates/tokio) async runtime, implies `futures`, //! - `async-std`: enables support for the [async-std](https://crates.io/crates/async-std) async runtime, implies `futures`, //! - `wasm-bindgen`: enabled support for [wasm-bindgen](https://crates.io/crates/wasm-bindgen). pub mod backoff; mod clock; pub mod default; mod error; pub mod exponential; #[cfg(feature = "futures")] #[cfg_attr(docsrs, doc(cfg(feature = "futures")))] pub mod future; mod retry; pub use crate::clock::{Clock, SystemClock}; pub use crate::error::Error; pub use crate::retry::{retry, retry_notify, Notify}; /// Exponential backoff policy with system's clock. /// /// This type is preferred over /// `exponential::ExponentialBackoff` as it is generic over any [Clocks](trait.Clock.html) /// and in the real world mostly system's clock is used. pub type ExponentialBackoff = exponential::ExponentialBackoff; /// Builder for exponential backoff policy with system's clock. pub type ExponentialBackoffBuilder = exponential::ExponentialBackoffBuilder; backoff-0.4.0/src/retry.rs000064400000000000000000000065460000000000000135120ustar 00000000000000use std::thread; use std::time::Duration; use crate::backoff::Backoff; use crate::error::Error; /// Retries this operation according to the backoff policy. /// backoff is reset before it is used. /// /// # Examples /// /// ```rust /// # use backoff::{ExponentialBackoff, Error, retry}; /// let f = || -> Result<(), Error<&str>> { /// // Business logic... /// // Give up. /// Err(Error::Permanent("error")) /// }; /// /// let backoff = ExponentialBackoff::default(); /// let _ = retry(backoff, f).err().unwrap(); /// ``` pub fn retry(backoff: B, op: F) -> Result> where F: FnMut() -> Result>, B: Backoff, { let mut retry = Retry { backoff, notify: NoopNotify, sleep: ThreadSleep, }; retry.retry_notify(op) } /// Retries this operation according to the backoff policy. /// Calls notify on failed attempts (in case of transient errors). /// backoff is reset before it is used. /// /// # Examples /// /// ```rust /// # use backoff::{Error, retry_notify}; /// # use backoff::backoff::Stop; /// # use std::time::Duration; /// let notify = |err, dur| { println!("Error happened at {:?}: {}", dur, err); }; /// let f = || -> Result<(), Error<&str>> { /// // Business logic... /// Err(Error::transient("error")) /// }; /// /// let backoff = Stop{}; /// let _ = retry_notify(backoff, f, notify).err().unwrap(); /// ``` pub fn retry_notify(backoff: B, op: F, notify: N) -> Result> where F: FnMut() -> Result>, B: Backoff, N: Notify, { let mut retry = Retry { backoff, notify, sleep: ThreadSleep, }; retry.retry_notify(op) } struct Retry { backoff: B, notify: N, sleep: S, } impl Retry { pub fn retry_notify(&mut self, mut op: F) -> Result> where F: FnMut() -> Result>, B: Backoff, N: Notify, S: Sleep, { self.backoff.reset(); loop { let err = match op() { Ok(v) => return Ok(v), Err(err) => err, }; let (err, next) = match err { Error::Permanent(err) => return Err(Error::Permanent(err)), Error::Transient { err, retry_after } => { match retry_after.or_else(|| self.backoff.next_backoff()) { Some(next) => (err, next), None => return Err(Error::transient(err)), } } }; self.notify.notify(err, next); self.sleep.sleep(next); } } } trait Sleep { fn sleep(&mut self, dur: Duration); } struct ThreadSleep; impl Sleep for ThreadSleep { fn sleep(&mut self, dur: Duration) { thread::sleep(dur); } } /// Notify is called in [`retry_notify`](trait.Operation.html#method.retry_notify) in case of errors. pub trait Notify { fn notify(&mut self, err: E, duration: Duration); } impl Notify for F where F: FnMut(E, Duration), { fn notify(&mut self, err: E, duration: Duration) { self(err, duration) } } /// No-op implementation of [`Notify`]. Literally does nothing. #[derive(Debug, Clone, Copy)] pub struct NoopNotify; impl Notify for NoopNotify { fn notify(&mut self, _: E, _: Duration) {} } backoff-0.4.0/tests/exponential.rs000064400000000000000000000054030000000000000152350ustar 00000000000000extern crate backoff; extern crate instant; use backoff::backoff::Backoff; use backoff::exponential::ExponentialBackoff; use backoff::{Clock, SystemClock}; use instant::Instant; use std::cell::RefCell; use std::time::Duration; struct Inner { i: Duration, start: Instant, } struct TestClock(RefCell); impl TestClock { fn new(i: Duration, start: Instant) -> TestClock { TestClock(RefCell::new(Inner { i: i, start: start })) } } impl Clock for TestClock { fn now(&self) -> Instant { let mut inner = self.0.borrow_mut(); let t = inner.start + inner.i; inner.i += Duration::from_secs(1); t } } impl Default for TestClock { fn default() -> Self { TestClock::new(Duration::from_secs(1), Instant::now()) } } #[test] fn get_elapsed_time() { let mut exp = ExponentialBackoff::default(); exp.clock = TestClock::new(Duration::new(0, 0), Instant::now()); exp.reset(); let elapsed_time = exp.get_elapsed_time(); assert_eq!(elapsed_time, Duration::new(1, 0)); } #[test] fn max_elapsed_time() { let mut exp = ExponentialBackoff::default(); exp.clock = TestClock::new(Duration::new(0, 0), Instant::now()); // Change the currentElapsedTime to be 0 ensuring that the elapsed time will be greater // than the max elapsed time. exp.start_time = Instant::now() - Duration::new(1000, 0); assert!(exp.next_backoff().is_none()); // https://github.com/ihrwein/backoff/issues/42 // This sets up an ExponentialBackoff that has been retrying for 900ms, // will next try for >= 500ms, which would put it after the 1000ms // max_elapsed_time. let clock = SystemClock::default(); let mut exp = ExponentialBackoff { max_elapsed_time: Some(Duration::from_secs(1)), current_interval: Duration::from_millis(500), start_time: clock.now() - Duration::from_millis(900), clock, ..ExponentialBackoff::default() }; assert_eq!( None, exp.next_backoff(), "Should not provide a backoff interval if it would be beyond max_elapsed_time" ); } #[test] fn backoff() { let mut exp = ExponentialBackoff::::default(); exp.initial_interval = Duration::from_millis(500); exp.randomization_factor = 0.1; exp.multiplier = 2.0; exp.max_interval = Duration::from_secs(5); exp.max_elapsed_time = Some(Duration::new(16 * 60, 0)); exp.reset(); let expected_results_millis = [500, 1000, 2000, 4000, 5000, 5000, 5000, 5000, 5000, 5000]; let expected_results = expected_results_millis .iter() .map(|&ms| Duration::from_millis(ms)) .collect::>(); for i in expected_results { assert_eq!(i, exp.current_interval); exp.next_backoff(); } } backoff-0.4.0/tests/retry.rs000064400000000000000000000020000000000000000140420ustar 00000000000000extern crate backoff; use backoff::Error; use backoff::ExponentialBackoff; use std::io; #[test] fn retry() { let mut i = 0; let success_on = 3; { let f = || -> Result<(), Error> { i += 1; if i == success_on { return Ok(()); } Err(Error::Transient { err: io::Error::new(io::ErrorKind::Other, "err"), retry_after: None, }) }; let backoff = ExponentialBackoff::default(); backoff::retry(backoff, f).ok().unwrap(); } assert_eq!(i, success_on); } #[test] fn permanent_error_immediately_returned() { let f = || -> Result<(), Error> { Err(Error::Permanent(io::Error::new( io::ErrorKind::Other, "err", ))) }; let backoff = ExponentialBackoff::default(); match backoff::retry(backoff, f).err().unwrap() { Error::Permanent(_) => (), other => panic!("{}", other), } }