Throttle request using bottleneck

Also reformat + renames
This commit is contained in:
2018-06-06 15:04:09 +05:30
parent 2dcc3b5d03
commit dfeb5f7a96
3 changed files with 118 additions and 47 deletions
+1
View File
@@ -33,6 +33,7 @@
}, },
"dependencies": { "dependencies": {
"@octokit/rest": "^15.6.2", "@octokit/rest": "^15.6.2",
"bottleneck": "^2.3.1",
"octonode": "^0.9.2" "octonode": "^0.9.2"
}, },
"devDependencies": { "devDependencies": {
+98 -32
View File
@@ -1,26 +1,79 @@
import rest = require('@octokit/rest'); import * as Octokit from '@octokit/rest';
import assert = require('assert'); import assert = require('assert');
import Bottleneck from 'bottleneck';
const octokit = new rest(); const octokit = new Octokit() as OctokitMod;
// Add rate limiter
const limiter = new Bottleneck({
maxConcurrent: 10,
minTime: 50,
});
const noop = () => Promise.resolve();
octokit.hook.before('request', limiter.schedule.bind(limiter, noop));
// Add key and secret for query
octokit.authenticate({ octokit.authenticate({
type: 'oauth', type: 'oauth',
key: '05e5f5ec65387c49137b', key: '05e5f5ec65387c49137b',
secret: '2228539a48032f0622d6c12a66f56253d0a30d60', secret: '2228539a48032f0622d6c12a66f56253d0a30d60',
}); });
interface RequestOptions {
method: string;
url: string;
headers: any;
query?: string;
variables?: Variables;
}
interface Result {
headers: {
status: string;
};
}
interface OctokitError {
code: number;
status: string;
}
interface OctokitMod extends Octokit {
// The following are added because Octokit does not expose the hook.error, hook.before, and hook.after methods
hook: {
error: (
when: 'request',
callback: (error: OctokitError, options: RequestOptions) => void
) => void;
before: (
when: 'request',
callback: (result: Result, options: RequestOptions) => void
) => void;
after: (
when: 'request',
callback: (result: Result, options: RequestOptions) => void
) => void;
};
}
interface Variables {
[key: string]: any;
}
interface ResponseWithDataArray<T> { interface ResponseWithDataArray<T> {
data: T[]; data: T[];
} }
interface ResponseWithMetaLink { interface ResponseWithMetaLink {
meta: { meta: {
link: string link: string;
}; };
} }
interface ResponseWithDataArrayAndMeta<T> extends ResponseWithDataArray<T>, ResponseWithMetaLink { interface ResponseWithDataArrayAndMeta<T>
extends ResponseWithDataArray<T>,
} ResponseWithMetaLink {}
interface ResponseFromGetUserRepo extends ResponseWithMetaLink { interface ResponseFromGetUserRepo extends ResponseWithMetaLink {
data: RepoFromGetUserRepo[]; data: RepoFromGetUserRepo[];
@@ -110,19 +163,20 @@ interface RepoNameWithParentRepo {
interface RepoNameWithBranchesAndParent interface RepoNameWithBranchesAndParent
extends RepoNameWithBranches, extends RepoNameWithBranches,
RepoNameWithParentRepo { } RepoNameWithParentRepo {}
const username = 'bendtherules'; const username = 'rousan';
interface ObjectWithPerPage { interface ObjectWithPerPage {
per_page?: number; per_page?: number;
} }
async function paginate<TFirstParam extends ObjectWithPerPage, TDataElement>( async function paginate<TFirstParam extends ObjectWithPerPage, TDataElement>(
method: (args: TFirstParam) => Promise<ResponseWithDataArrayAndMeta<TDataElement>>, method: (
args: TFirstParam
) => Promise<ResponseWithDataArrayAndMeta<TDataElement>>,
args: TFirstParam args: TFirstParam
): Promise<ResponseWithDataArray<TDataElement>> { ): Promise<ResponseWithDataArray<TDataElement>> {
// Set per_page // Set per_page
args.per_page = 100; args.per_page = 100;
@@ -136,25 +190,27 @@ async function paginate<TFirstParam extends ObjectWithPerPage, TDataElement>(
} }
return { return {
data data,
}; };
} }
async function fetchRepoNameWithBranches( async function fetchRepoNameWithBranches(
repoName: string repoName: string
): Promise<RepoNameWithBranches> { ): Promise<RepoNameWithBranches> {
const params: rest.ReposGetBranchesParams = { const params: Octokit.ReposGetBranchesParams = {
owner: username, owner: username,
repo: repoName, repo: repoName,
}; };
const branchesResponse: ResponseWithDataArray<BranchFromGetBranches> = const branchesResponse: ResponseWithDataArray<
await paginate( BranchFromGetBranches
(tmpFirstParam: rest.ReposGetBranchesParams): Promise<ResponseFromGetBranches> => { > = await paginate((tmpFirstParam: Octokit.ReposGetBranchesParams): Promise<
return octokit.repos.getBranches(tmpFirstParam) as any as Promise<ResponseFromGetBranches>; ResponseFromGetBranches
}, > => {
params return (octokit.repos.getBranches(tmpFirstParam) as any) as Promise<
); ResponseFromGetBranches
>;
}, params);
return { return {
repoName, repoName,
@@ -254,26 +310,33 @@ async function fetchNoneOfForkBranchesIsAhead(
async function fetchUserIsNotContributor( async function fetchUserIsNotContributor(
repoName: string repoName: string
): Promise<RepoNameWithUnusedFlag> { ): Promise<RepoNameWithUnusedFlag> {
const params: rest.ReposGetContributorsParams = { const params: Octokit.ReposGetContributorsParams = {
owner: username, owner: username,
repo: repoName, repo: repoName,
anon: '0', anon: '0',
}; };
const responseFromGetContributors: ResponseWithDataArray<OwnerFromGetContributors> = const responseFromGetContributors: ResponseWithDataArray<
await paginate( OwnerFromGetContributors
async (tmpFirstParam: rest.ReposGetContributorsParams): Promise<ResponseWithDataArrayAndMeta<OwnerFromGetContributors>> => { > = await paginate(
async (
tmpFirstParam: Octokit.ReposGetContributorsParams
): Promise<ResponseWithDataArrayAndMeta<OwnerFromGetContributors>> => {
// Modify getContributors to return empty contributor data array instead of undefined for empty repos // Modify getContributors to return empty contributor data array instead of undefined for empty repos
const response = await (octokit.repos.getContributors(tmpFirstParam) as any as Promise<ResponseFromGetContributors>); const response = await ((octokit.repos.getContributors(
tmpFirstParam
) as any) as Promise<ResponseFromGetContributors>);
let dataNormalized = response.data; let dataNormalized = response.data;
if (dataNormalized === undefined) { if (dataNormalized === undefined) {
dataNormalized = []; dataNormalized = [];
} }
const responseNormalized: ResponseWithDataArrayAndMeta<OwnerFromGetContributors> = { const responseNormalized: ResponseWithDataArrayAndMeta<
OwnerFromGetContributors
> = {
data: dataNormalized, data: dataNormalized,
meta: response.meta meta: response.meta,
}; };
return responseNormalized; return responseNormalized;
@@ -295,14 +358,17 @@ async function fetchUserIsNotContributor(
} }
async function fetchUnusedForkedRepos() { async function fetchUnusedForkedRepos() {
const params: rest.ReposGetForUserParams = { const params: Octokit.ReposGetForUserParams = {
username, username,
} };
const repos: ResponseWithDataArray<RepoFromGetUserRepo> = const repos: ResponseWithDataArray<RepoFromGetUserRepo> = await paginate(
await paginate( (
(tmpFirstParam: rest.ReposGetForUserParams): Promise<ResponseFromGetUserRepo> => { tmpFirstParam: Octokit.ReposGetForUserParams
return octokit.repos.getForUser(tmpFirstParam) as any as Promise<ResponseFromGetUserRepo>; ): Promise<ResponseFromGetUserRepo> => {
return (octokit.repos.getForUser(tmpFirstParam) as any) as Promise<
ResponseFromGetUserRepo
>;
}, },
params params
); );
+4
View File
@@ -991,6 +991,10 @@ boom@2.x.x:
dependencies: dependencies:
hoek "2.x.x" hoek "2.x.x"
bottleneck@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.3.1.tgz#16292092ff040ccbf2d05d0a09d69eab7b1c46bc"
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"