Skip to content

Commit f3390b4

Browse files
Update gitlab limits and correctly use the rate limit error
1 parent c65d1e5 commit f3390b4

File tree

3 files changed

+36
-17
lines changed

3 files changed

+36
-17
lines changed

src/repositories/github.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use reqwest::{
99
use serde::Deserialize;
1010

1111
use crate::repositories::{
12-
FetchRepositoriesResult, Repository, RepositoryForge, RepositoryName, APP_USER_AGENT,
12+
FetchRepositoriesResult, RateLimitReached, Repository, RepositoryForge, RepositoryName,
13+
APP_USER_AGENT,
1314
};
1415

1516
const GRAPHQL_UPDATE: &str = "query($ids: [ID!]!) {
@@ -182,10 +183,6 @@ impl GitHub {
182183
}
183184
}
184185

185-
#[derive(Debug, failure::Fail)]
186-
#[fail(display = "rate limit reached")]
187-
struct RateLimitReached;
188-
189186
#[derive(Debug, Deserialize)]
190187
struct GraphResponse<T> {
191188
data: T,

src/repositories/gitlab.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ use reqwest::{
77
};
88
use serde::Deserialize;
99
use std::collections::HashSet;
10+
use std::str::FromStr;
1011

1112
use crate::repositories::{
12-
FetchRepositoriesResult, Repository, RepositoryForge, RepositoryName, APP_USER_AGENT,
13+
FetchRepositoriesResult, RateLimitReached, Repository, RepositoryForge, RepositoryName,
14+
APP_USER_AGENT,
1315
};
1416

1517
const GRAPHQL_UPDATE: &str = "query($ids: [ID!]!) {
@@ -76,18 +78,19 @@ impl RepositoryForge for GitLab {
7678
}
7779

7880
fn chunk_size(&self) -> usize {
79-
5
81+
100
8082
}
8183

8284
fn fetch_repository(&self, name: &RepositoryName) -> Result<Option<Repository>> {
8385
let project_path = format!("{}/{}", name.owner, name.repo);
8486
// Fetch the latest information from the Gitlab API.
85-
let response: GraphResponse<GraphProjectNode> = self.graphql(
87+
let response: (GraphResponse<GraphProjectNode>, Option<usize>) = self.graphql(
8688
GRAPHQL_SINGLE,
8789
serde_json::json!({
8890
"fullPath": &project_path,
8991
}),
9092
)?;
93+
let (response, rate_limit) = response;
9194
if let Some(repo) = response.data.and_then(|d| d.project) {
9295
Ok(Some(Repository {
9396
id: repo.id,
@@ -98,18 +101,24 @@ impl RepositoryForge for GitLab {
98101
forks: repo.forks_count,
99102
issues: repo.open_issues_count.unwrap_or(0),
100103
}))
104+
} else if rate_limit.map(|x| x < 1).unwrap_or(false) {
105+
Err(RateLimitReached.into())
101106
} else {
102107
Ok(None)
103108
}
104109
}
105110

106111
fn fetch_repositories(&self, ids: &[String]) -> Result<FetchRepositoriesResult> {
107-
let response: GraphResponse<GraphProjects<Option<GraphProject>>> = self.graphql(
112+
let response: (
113+
GraphResponse<GraphProjects<Option<GraphProject>>>,
114+
Option<usize>,
115+
) = self.graphql(
108116
GRAPHQL_UPDATE,
109117
serde_json::json!({
110118
"ids": ids,
111119
}),
112120
)?;
121+
let (response, rate_limit) = response;
113122
let mut ret = FetchRepositoriesResult::default();
114123
// When gitlab doesn't find an ID, it simply doesn't list it. So we need to actually check
115124
// which nodes remain at the end to delete their DB entry.
@@ -136,6 +145,10 @@ impl RepositoryForge for GitLab {
136145
}
137146
}
138147

148+
if ret.present.is_empty() && rate_limit.map(|x| x < 1).unwrap_or(false) {
149+
return Err(RateLimitReached.into());
150+
}
151+
139152
// Those nodes were not returned by gitlab, meaning they don't exist (anymore?).
140153
ret.missing = node_ids.into_iter().map(|s| s.to_owned()).collect();
141154

@@ -151,24 +164,29 @@ impl GitLab {
151164
&self,
152165
query: &str,
153166
variables: impl serde::Serialize,
154-
) -> Result<GraphResponse<T>> {
155-
Ok(self
167+
) -> Result<(GraphResponse<T>, Option<usize>)> {
168+
let res = self
156169
.client
157170
.post(&format!("https://{}/api/graphql", self.host))
158171
.json(&serde_json::json!({
159172
"query": query,
160173
"variables": variables,
161174
}))
162175
.send()?
163-
.error_for_status()?
164-
.json()?)
176+
.error_for_status()?;
177+
// There are a few other header values that might interesting so keeping them here:
178+
// * RateLimit-Observed: '1'
179+
// * RateLimit-Remaining: '1999'
180+
// * RateLimit-ResetTime: 'Wed, 10 Feb 2021 21:31:42 GMT'
181+
// * RateLimit-Limit: '2000'
182+
let rate_limit = res
183+
.headers()
184+
.get("RateLimit-Remaining")
185+
.and_then(|x| usize::from_str(x.to_str().ok()?).ok());
186+
Ok((res.json()?, rate_limit))
165187
}
166188
}
167189

168-
#[derive(Debug, failure::Fail)]
169-
#[fail(display = "rate limit reached")]
170-
struct RateLimitReached;
171-
172190
#[derive(Debug, Deserialize)]
173191
struct GraphProjects<T> {
174192
projects: GraphNodes<T>,

src/repositories/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ pub const APP_USER_AGENT: &str = concat!(
1111
include_str!(concat!(env!("OUT_DIR"), "/git_version"))
1212
);
1313

14+
#[derive(Debug, failure::Fail)]
15+
#[fail(display = "rate limit reached")]
16+
struct RateLimitReached;
17+
1418
mod github;
1519
mod gitlab;
1620
mod updater;

0 commit comments

Comments
 (0)