~jplatte/skill-tree-upd

9d73bf3498ddb891646c93db8c29e987c91d163d — Jonas Platte 10 months ago 76caccd master
Retry on network / remote failure
1 files changed, 54 insertions(+), 31 deletions(-)

M src/main.rs
M src/main.rs => src/main.rs +54 -31
@@ 1,6 1,6 @@
// GET /repos/:owner/:repo/pulls/:pull_number/merge
#![feature(async_closure)]

use std::time::Duration;
use std::{future::Future, time::Duration};

use anyhow::Context;
use serde::Deserialize;


@@ 20,17 20,20 @@ async fn main() -> anyhow::Result<()> {

    #[allow(clippy::never_loop)]
    loop {
        let pr_status: PrInfo = client
            .get(&format!(
                "https://api.github.com/repos/{}/pulls/{}",
                REPO, PR_ID
            ))
            .send()
            .await
            .context("requesting PR status")?
            .json()
            .await
            .context("deserializing PR status")?;
        let pr_status: PrInfo = retry_twice(async || {
            client
                .get(&format!(
                    "https://api.github.com/repos/{}/pulls/{}",
                    REPO, PR_ID
                ))
                .send()
                .await
        })
        .await
        .context("requesting PR status")?
        .json()
        .await
        .context("deserializing PR status")?;

        if pr_status.merged {
            // PR has been merged, stop looking for updates.


@@ 40,17 43,20 @@ async fn main() -> anyhow::Result<()> {
        if pr_status.head.sha != last_sha {
            last_sha = pr_status.head.sha;

            let files: Vec<PrFile> = client
                .get(&format!(
                    "https://api.github.com/repos/{}/pulls/{}/files",
                    REPO, PR_ID
                ))
                .send()
                .await
                .context("requesting pr files")?
                .json()
                .await
                .context("deserializing pr files")?;
            let files: Vec<PrFile> = retry_twice(async || {
                client
                    .get(&format!(
                        "https://api.github.com/repos/{}/pulls/{}/files",
                        REPO, PR_ID
                    ))
                    .send()
                    .await
            })
            .await
            .context("requesting pr files")?
            .json()
            .await
            .context("deserializing pr files")?;

            let skill_tree_toml_url = &files
                .iter()


@@ 58,13 64,10 @@ async fn main() -> anyhow::Result<()> {
                .context("no file ending in tree.toml found")?
                .raw_url;

            let skill_tree_toml = client
                .get(skill_tree_toml_url)
                .send()
                .await?
                .bytes()
                .await
                .context("receiving skill tree toml")?;
            let skill_tree_toml =
                retry_twice(async || client.get(skill_tree_toml_url).send().await?.bytes().await)
                    .await
                    .context("receiving skill tree toml")?;

            // we're in a working directory where we can just let files sit around
            fs::write("skill-tree.toml", skill_tree_toml).await?;


@@ 84,6 87,26 @@ async fn main() -> anyhow::Result<()> {
    Ok(())
}

async fn retry_twice<T, E, Fn, Fut>(mut f: Fn) -> Result<T, E>
where
    Fn: FnMut() -> Fut,
    Fut: Future<Output = Result<T, E>>,
{
    match f().await {
        Ok(res) => return Ok(res),
        // First delay: one minute
        Err(_) => time::delay_for(Duration::from_secs(60)).await,
    }

    match f().await {
        Ok(res) => return Ok(res),
        // Second delay: 10 minutes
        Err(_) => time::delay_for(Duration::from_secs(10 * 60)).await,
    }

    f().await
}

// The fields of the API responses that we are interested in
#[derive(Debug, Deserialize)]
struct PrInfo {