Skip to content

Commit

Permalink
Add a LOT more error handling to all async logics
Browse files Browse the repository at this point in the history
  • Loading branch information
jayantbh committed Dec 12, 2023
1 parent c5537f2 commit 0f32197
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 26 deletions.
1 change: 1 addition & 0 deletions libdefs/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ declare type DateString = string;

declare namespace NodeJS {
export interface ProcessEnv {
NEXT_PUBLIC_APP_ENVIRONMENT: 'production' | 'development';
NEXTAUTH_URL: string;
NEXTAUTH_SECRET: string;
GITHUB_ID: string;
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"build": "./scripts/build.sh",
"zip": "./scripts/zip.sh",
"box-server-start-wo-install": "./scripts/server-init.sh",
"box-server-start": "yarn install && yarn box-server-start-wo-install"
"box-server-start": "yarn install && yarn box-server-start-wo-install",
"qc": "yarn tsc && yarn lint"
},
"dependencies": {
"@sentry/nextjs": "^7.86.0",
Expand Down
6 changes: 5 additions & 1 deletion src/analytics/pr-analytics.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { ResponseError } from '@/utils/errors';
import { PullRequestEdge, PullRequest } from '../api-helpers/exapi-sdk/types';
import { getTopNKeys } from './utils';
import { logException } from '@/utils/logger';

export const getPRListAndMonthlyCountsFromGqlResponse = (
edges?: PullRequestEdge[][]
) => {
if (!edges) throw new ResponseError('No data found to calculate stats', 404);
if (!edges) {
logException('No data found to calculate stats');
throw new ResponseError('No data found to calculate stats', 404);
}

const flat_prs = edges.flat().map((pr_node) => pr_node.node);
const prs_monthly_counts = edges.map((monthly_prs) => monthly_prs.length);
Expand Down
18 changes: 14 additions & 4 deletions src/api-helpers/exapi-sdk/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from './types';
import { GithubContributionCalendar } from '@/api-helpers/exapi-sdk/types';
import { captureException } from '@sentry/nextjs';
import { logException } from '@/utils/logger';

async function fetchPullRequestsForMonth(
author: string,
Expand Down Expand Up @@ -111,7 +112,7 @@ export async function fetchAllPullRequests(author: string, token: string) {
);
return results;
} catch (error: any) {
console.error('Error fetching data:', error.message);
logException('Error fetching PRs', { originalException: error });
}
}

Expand All @@ -128,6 +129,9 @@ export async function fetchUser(token: string) {
const userData: GithubUser = response.data;
return userData;
} catch (error: any) {
logException(`Error fetching user data: ${error.message}`, {
originalException: error
});
throw new Error(`Error fetching user data: ${error.message}`);
}
}
Expand Down Expand Up @@ -232,7 +236,9 @@ export async function fetchAllReviewedPRs(author: string, token: string) {
);
return results;
} catch (error: any) {
console.error('Error fetching reviews:', error.message);
logException('Error fetching reviews for ' + author, {
originalException: error
});
}
}

Expand Down Expand Up @@ -278,7 +284,9 @@ export async function fetchUserGitHubContributionCalendarMetrics(

if (collection) return collection.contributionCalendar;
} catch (error: any) {
console.error('Error fetching GitHub metrics:', error.message);
logException('Error fetching GitHub metrics for ' + author, {
originalException: error
});
}
return { totalContributions: 0, weeks: [] };
}
Expand Down Expand Up @@ -318,7 +326,9 @@ export async function fetchUserContributionSummaryMetrics(

return response.data.data.user.contributionsCollection;
} catch (error: any) {
console.error('Error fetching GitHub metrics:', error.message);
logException('Error fetching GitHub metrics for ' + author, {
originalException: error
});
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/api-helpers/image-gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createImageUsingVercel } from './vercel-generator';
import { getDataFromGithubResponse } from '@/api-helpers/card-data-adapter';
import { CardTypes, sequence } from '../types/cards';
import { ImageFile } from '@/types/images';
import { logException } from '@/utils/logger';

export const generateImages = async (
data: GitHubDataResponse,
Expand Down Expand Up @@ -31,6 +32,7 @@ export const generateImages = async (
return imageFileBuffers;
} catch (error) {
console.error('Error in generateImages:', error);
logException('Error in generateImages', { originalException: error });
throw new Error('Image generation failed');
}
};
14 changes: 8 additions & 6 deletions src/api-helpers/vercel-generator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { CardTemplate, CardTemplateData } from '../components/templates';
import { getFontsForImageGeneration } from './fonts';
import { SCALE_FACTOR } from '@/constants/general';
import { logException } from '@/utils/logger';

export const createImageUsingVercel = async (
data: CardTemplateData['data'],
Expand Down Expand Up @@ -40,11 +41,10 @@ export const createImageUsingVercel = async (

try {
imageArrayBuffer = await generatedImage.arrayBuffer();
} catch (arrayBufferError) {
console.error(
`Error converting image to array buffer for ${cardType}:`,
arrayBufferError
);
} catch (error) {
logException('Error converting image to array buffer for ${cardType}', {
originalException: error
});
throw new Error(`Image buffer creation failed for ${cardType}`);
}

Expand All @@ -56,7 +56,9 @@ export const createImageUsingVercel = async (
image: imageCopy
};
} catch (error) {
console.error(`Error in createImageUsingVercel for ${cardType}:`, error);
logException(`Error in createImageUsingVercel for ${cardType}:`, {
originalException: error
});
throw new Error(`Image creation failed for ${cardType}`);
}
};
3 changes: 2 additions & 1 deletion src/components/ShareButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {} from 'react-icons';
import { FaTwitter, FaDownload } from 'react-icons/fa';
import toast from 'react-hot-toast';
import { track } from '@/constants/events';
import { logException } from '@/utils/logger';

type ShareButtonProps = {
imageUrl?: string;
Expand Down Expand Up @@ -113,7 +114,7 @@ const CopyPaperClip: React.FC<{ textToCopy: string }> = ({ textToCopy }) => {
}, 2000);
track('SINGLE_IMAGE_PUBLIC_LINK_COPIED');
} catch (err) {
console.error('Error copying to clipboard:', err);
logException('Error copying to clipboard', { originalException: err });
}
};

Expand Down
2 changes: 2 additions & 0 deletions src/contexts/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React, {
} from 'react';
import { useRouter } from 'next/router';
import { useSession } from 'next-auth/react';
import { logException } from '@/utils/logger';

interface AppStateInterface {
isLoading: boolean;
Expand Down Expand Up @@ -40,6 +41,7 @@ export const AppStateProvider = ({ children }: AppStateProviderInterface) => {
export const useAppState = () => {
const context = useContext(AppStateContext);
if (!context) {
logException('useGlobalState must be used within a GlobalStateContext');
throw new Error('useGlobalState must be used within a GlobalStateContext');
}
return context;
Expand Down
9 changes: 7 additions & 2 deletions src/hooks/useImageDownloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import JSZip from 'jszip';
import { saveAs } from 'file-saver';
import { useCallback } from 'react';
import { UpdatedImageFile } from '@/types/images';
import { logException } from '@/utils/logger';

interface DownloadImagesProps {
images: UpdatedImageFile | UpdatedImageFile[];
Expand All @@ -11,7 +12,9 @@ const downloadSingleImage = (image: UpdatedImageFile) => {
fetch(image.data)
.then((response) => response.blob())
.then((blob) => saveAs(blob, fileName))
.catch((error) => console.error('Error downloading image:', error));
.catch((error) =>
logException('Error downloading image:', { originalException: error })
);
};

const downloadMultipleImages = (images: UpdatedImageFile[]) => {
Expand All @@ -27,7 +30,9 @@ const downloadMultipleImages = (images: UpdatedImageFile[]) => {
Promise.all(promises)
.then(() => zip.generateAsync({ type: 'blob' }))
.then((content) => saveAs(content, 'unwrapped-images.zip'))
.catch((error) => console.error('Error zipping images:', error));
.catch((error) =>
logException('Error zipping images:', { originalException: error })
);
};

export const useImageDownloader = () => {
Expand Down
4 changes: 4 additions & 0 deletions src/pages/api/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
bcryptGen,
extractFilenameWithoutExtension
} from '@/utils/stringHelpers';
import { logException } from '@/utils/logger';

const fetchAndDownloadImageBuffer = async (
req: NextApiRequest,
Expand Down Expand Up @@ -79,6 +80,9 @@ const fetchAndDownloadImageBuffer = async (
}
console.log(chalk.green('Successfully sent buffer to client'));
} catch (error: any) {
logException('Error fetching or sending buffer', {
originalException: error
});
console.log(chalk.red('Error fetching or sending buffer:'), error);
res.status(error.status || 500).json({ message: error.message });
}
Expand Down
4 changes: 1 addition & 3 deletions src/utils/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ export const handleRequest = <T = any>(
export const handleThen = (r: AxiosResponse) => r.data;

export const handleCatch = (err: AxiosError) => {
if (process.env.NODE_ENV === 'production') {
logException(err);
}
logException(err);
throw err.response;
};
5 changes: 4 additions & 1 deletion src/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function logException(
exc: string | Error,
msgOrCtx?: string | CaptureCtx,
ctx?: CaptureCtx
): CaptureExc {
): CaptureExc | void {
const message = typeof msgOrCtx === 'string' ? msgOrCtx : undefined;
const context = typeof msgOrCtx === 'object' ? msgOrCtx : ctx;
const name = (() => {
Expand All @@ -43,6 +43,9 @@ export function logException(
err.name = name;
if (stack) err.stack = stack;

if (process.env.NEXT_PUBLIC_APP_ENVIRONMENT !== 'production')
return console.error(err);

return captureException(err, {
...context,
extra: {
Expand Down
27 changes: 21 additions & 6 deletions src/utils/persistence/file-system.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ImageFile } from '@/types/images';
import fs from 'fs/promises';
import path from 'path';
import { logException } from '../logger';

async function directoryExists(localDirectory: string): Promise<boolean> {
try {
Expand All @@ -17,9 +18,11 @@ async function ensureDirectoryExists(localDirectory: string) {
console.log(`Directory created: ${localDirectory}`);
} catch (error: any) {
if (error.code === 'EEXIST') {
console.log(`Directory already exists: ${localDirectory}`);
console.error(`Directory already exists: ${localDirectory}`);
} else {
console.error(`Error creating directory: ${error.message}`);
logException(`Error creating directory: ${error.message}`, {
originalException: error
});
}
}
}
Expand All @@ -38,9 +41,10 @@ export const saveImagesToLocalDirectory = async (

await Promise.all(savePromises);
} catch (error: any) {
throw new Error(
`Error fetching images from local directory: ${error.message}`
);
logException(`Error saving images to local directory: ${error.message}`, {
originalException: error
});
throw new Error(`Error saving images to local directory: ${error.message}`);
}
};

Expand All @@ -63,6 +67,10 @@ export const fetchImagesFromLocalDirectory = async (

return images;
} catch (error: any) {
logException(
`Error fetching images from local directory: ${error.message}`,
{ originalException: error }
);
throw new Error(
`Error fetching images from local directory: ${error.message}`
);
Expand All @@ -79,8 +87,12 @@ export const fetchImageFromLocalDirectory = async (
data
};
} catch (error: any) {
logException(
`Error fetching single image from local directory: ${error.message}`,
{ originalException: error }
);
throw new Error(
`Error fetching images from local directory: ${error.message}`
`Error fetching single image from local directory: ${error.message}`
);
}
};
Expand All @@ -94,6 +106,9 @@ export const deleteLocalDirectory = async (

await fs.rmdir(localDirectory, { recursive: true });
} catch (error: any) {
logException(`Error deleting local directory: ${error.message}`, {
originalException: error
});
throw new Error(`Error deleting local directory: ${error.message}`);
}
};
15 changes: 14 additions & 1 deletion src/utils/persistence/s3.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ImageFile } from '@/types/images';
import { S3 } from 'aws-sdk';
import { logException } from '../logger';

const s3 = new S3({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
Expand All @@ -23,6 +24,9 @@ export const uploadImagesToS3 = async (
try {
await s3.upload(uploadParams).promise();
} catch (error: any) {
logException(`Error uploading image to S3: ${error.message}`, {
originalException: error
});
throw new Error(`Error uploading image to S3: ${error.message}`);
}
});
Expand Down Expand Up @@ -56,6 +60,9 @@ export const fetchImagesFromS3Directory = async (

return images;
} catch (error: any) {
logException(`Error fetching images from S3: ${error.message}`, {
originalException: error
});
throw new Error(`Error fetching images from S3: ${error.message}`);
}
};
Expand All @@ -74,7 +81,10 @@ export const fetchFileFromS3Directory = async (
data: imageBuffer.Body as Buffer
};
} catch (error: any) {
throw new Error(`Error fetching images from S3: ${error.message}`);
logException(`Error fetching file from S3: ${error.message}`, {
originalException: error
});
throw new Error(`Error fetching file from S3: ${error.message}`);
}
};

Expand All @@ -101,6 +111,9 @@ export const deleteS3Directory = async (
await s3.deleteObjects(deleteObjectsParams).promise();
}
} catch (error: any) {
logException(`Error deleting directory from S3: ${error.message}`, {
originalException: error
});
throw new Error(`Error deleting directory from S3: ${error.message}`);
}
};

0 comments on commit 0f32197

Please sign in to comment.