Skip to content

Commit 3048223

Browse files
committed
Execute ping-goals command in the background to avoid timeout & retry
1 parent 68ef80c commit 3048223

File tree

3 files changed

+53
-21
lines changed

3 files changed

+53
-21
lines changed

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ async fn serve_req(
168168
return Ok(Response::builder()
169169
.status(StatusCode::OK)
170170
.header("Content-Type", "application/json")
171-
.body(Body::from(triagebot::zulip::respond(&ctx, req).await))
171+
.body(Body::from(triagebot::zulip::respond(ctx, req).await))
172172
.unwrap());
173173
}
174174
if req.uri.path() != "/github-hook" {

src/zulip.rs

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use anyhow::{Context as _, format_err};
2222
use rust_team_data::v1::{TeamKind, TeamMember};
2323
use std::cmp::Reverse;
2424
use std::fmt::Write as _;
25+
use std::sync::Arc;
2526
use subtle::ConstantTimeEq;
2627
use tracing as log;
2728

@@ -88,7 +89,7 @@ struct Response {
8889
/// Top-level handler for Zulip webhooks.
8990
///
9091
/// Returns a JSON response.
91-
pub async fn respond(ctx: &Context, req: Request) -> String {
92+
pub async fn respond(ctx: Arc<Context>, req: Request) -> String {
9293
let content = match process_zulip_request(ctx, req).await {
9394
Ok(None) => {
9495
return serde_json::to_string(&ResponseNotRequired {
@@ -123,7 +124,7 @@ pub fn get_token_from_env() -> Result<String, anyhow::Error> {
123124
/// Processes a Zulip webhook.
124125
///
125126
/// Returns a string of the response, or None if no response is needed.
126-
async fn process_zulip_request(ctx: &Context, req: Request) -> anyhow::Result<Option<String>> {
127+
async fn process_zulip_request(ctx: Arc<Context>, req: Request) -> anyhow::Result<Option<String>> {
127128
let expected_token = get_token_from_env()?;
128129
if !bool::from(req.token.as_bytes().ct_eq(expected_token.as_bytes())) {
129130
anyhow::bail!("Invalid authorization.");
@@ -148,7 +149,7 @@ async fn process_zulip_request(ctx: &Context, req: Request) -> anyhow::Result<Op
148149
}
149150

150151
async fn handle_command<'a>(
151-
ctx: &'a Context,
152+
ctx: Arc<Context>,
152153
mut gh_id: u64,
153154
command: &'a str,
154155
message_data: &'a Message,
@@ -203,10 +204,12 @@ async fn handle_command<'a>(
203204
}
204205
ChatCommand::Whoami => whoami_cmd(&ctx, gh_id).await,
205206
ChatCommand::Lookup(cmd) => lookup_cmd(&ctx, cmd).await,
206-
ChatCommand::Work(cmd) => workqueue_commands(ctx, gh_id, cmd).await,
207-
ChatCommand::PingGoals(args) => ping_goals_cmd(ctx, gh_id, &args).await,
207+
ChatCommand::Work(cmd) => workqueue_commands(&ctx, gh_id, cmd).await,
208+
ChatCommand::PingGoals(args) => {
209+
ping_goals_cmd(ctx.clone(), gh_id, message_data, &args).await
210+
}
208211
ChatCommand::DocsUpdate => trigger_docs_update(message_data, &ctx.zulip),
209-
ChatCommand::TeamStats { name } => team_status_cmd(ctx, &name).await,
212+
ChatCommand::TeamStats { name } => team_status_cmd(&ctx, &name).await,
210213
};
211214

212215
let output = output?;
@@ -267,29 +270,58 @@ async fn handle_command<'a>(
267270
StreamCommand::Read => post_waiter(&ctx, message_data, WaitingMessage::start_reading())
268271
.await
269272
.map_err(|e| format_err!("Failed to await at this time: {e:?}")),
270-
StreamCommand::PingGoals(args) => ping_goals_cmd(ctx, gh_id, &args).await,
273+
StreamCommand::PingGoals(args) => ping_goals_cmd(ctx, gh_id, message_data, &args).await,
271274
StreamCommand::DocsUpdate => trigger_docs_update(message_data, &ctx.zulip),
272275
}
273276
}
274277
}
275278

276279
async fn ping_goals_cmd(
277-
ctx: &Context,
280+
ctx: Arc<Context>,
278281
gh_id: u64,
282+
message: &Message,
279283
args: &PingGoalsArgs,
280284
) -> anyhow::Result<Option<String>> {
281285
if project_goals::check_project_goal_acl(&ctx.team, gh_id).await? {
282-
ping_project_goals_owners(
283-
&ctx.github,
284-
&ctx.zulip,
285-
&ctx.team,
286-
false,
287-
args.threshold as i64,
288-
&format!("on {}", args.next_update),
289-
)
290-
.await
291-
.map_err(|e| format_err!("Failed to await at this time: {e:?}"))?;
292-
Ok(None)
286+
let args = args.clone();
287+
let message = message.clone();
288+
tokio::spawn(async move {
289+
let res = ping_project_goals_owners(
290+
&ctx.github,
291+
&ctx.zulip,
292+
&ctx.team,
293+
false,
294+
args.threshold as i64,
295+
&format!("on {}", args.next_update),
296+
)
297+
.await;
298+
299+
let status = match res {
300+
Ok(_res) => "OK".to_string(),
301+
Err(err) => {
302+
tracing::error!("ping_project_goals_owners: {err:?}");
303+
format!("ERROR\n\n```\n{err:#?}\n```\n")
304+
}
305+
};
306+
307+
let res = MessageApiRequest {
308+
recipient: Recipient::Private {
309+
id: message.sender_id,
310+
email: &message.sender_email,
311+
},
312+
content: &format!("End pinging project groups owners: {status}"),
313+
}
314+
.send(&ctx.zulip)
315+
.await;
316+
317+
if let Err(err) = res {
318+
tracing::error!(
319+
"error sending project goals ping reply: {err:?} for status: {status}"
320+
);
321+
}
322+
});
323+
324+
Ok(Some("Started pinging project groups owners...".to_string()))
293325
} else {
294326
Err(format_err!(
295327
"That command is only permitted for those running the project-goal program.",

src/zulip/commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ pub enum StreamCommand {
165165
DocsUpdate,
166166
}
167167

168-
#[derive(clap::Parser, Debug, PartialEq)]
168+
#[derive(clap::Parser, Debug, PartialEq, Clone)]
169169
pub struct PingGoalsArgs {
170170
/// Number of days before an update is considered stale
171171
pub threshold: u64,

0 commit comments

Comments
 (0)