Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Prod] Fix for the specialist role filter for topic frequency, SSDI additions, worker transactions #2276

Merged
merged 75 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
c32119e
first pass at ssdi backend
GarrettEHill Jun 11, 2024
b196ec2
lint
GarrettEHill Jun 11, 2024
9ac37ad
Update handlers.ts
GarrettEHill Jun 11, 2024
31def3e
updates
GarrettEHill Jun 13, 2024
91551ad
all filters are arrays
GarrettEHill Jun 13, 2024
4736fe4
all queries used in the ssdi must use only arrays for all flags to si…
GarrettEHill Jun 13, 2024
428e0da
adding regional restrictions
GarrettEHill Jun 13, 2024
36076ad
lint
GarrettEHill Jun 13, 2024
361d4e9
Update handlers.test.js
GarrettEHill Jun 13, 2024
485752f
Update handlers.test.js
GarrettEHill Jun 13, 2024
5042502
Merge branch 'main' into TTAHUB-3078/ssdi
GarrettEHill Jun 18, 2024
1ba1986
updates to functional
GarrettEHill Jun 18, 2024
99d6bd1
Merge branch 'main' into TTAHUB-3078/ssdi
GarrettEHill Jun 20, 2024
2761745
Update handlers.test.js
GarrettEHill Jun 20, 2024
aabe721
fix tests
GarrettEHill Jun 20, 2024
baef4f0
Update ssdi.ts
GarrettEHill Jun 20, 2024
d12a6e9
Update handlers.ts
GarrettEHill Jun 20, 2024
5eff653
more tests to reach 100% coverage
GarrettEHill Jun 20, 2024
345939e
Update handlers.test.js
GarrettEHill Jun 22, 2024
d3086f1
Merge branch 'main' into TTAHUB-3078/ssdi
GarrettEHill Jun 24, 2024
9d17fd8
first pass
GarrettEHill Jun 27, 2024
5bb9340
lint fixes
GarrettEHill Jun 27, 2024
03d7220
correct use
GarrettEHill Jun 27, 2024
5db7ec5
Merge branch 'main' into TTAHUB-3078/ssdi
GarrettEHill Jul 1, 2024
efbf45c
Update communication-logs.sql
GarrettEHill Jul 1, 2024
ffab8c4
plumbing referenceData
GarrettEHill Jul 1, 2024
9fb9baa
more fixes
GarrettEHill Jul 2, 2024
5a7f3e1
more fixes
GarrettEHill Jul 2, 2024
2bac373
Update transactionWrapper.js
GarrettEHill Jul 2, 2024
2259e60
Update transactionWrapper.ts
GarrettEHill Jul 2, 2024
431ec19
Update transactionWrapper.ts
GarrettEHill Jul 2, 2024
10fb3cf
Update index.test.js
GarrettEHill Jul 3, 2024
4e47f59
Update html.pug
GarrettEHill Jul 4, 2024
eaa4edf
Merge branch 'main' into TTAHUB-3097/worker-transactions
GarrettEHill Jul 4, 2024
5fb61f9
wrong order
GarrettEHill Jul 5, 2024
05c15e2
fixes
GarrettEHill Jul 9, 2024
ee10691
Update requestErrors.js
GarrettEHill Jul 9, 2024
971cf73
fix more tests
GarrettEHill Jul 10, 2024
3e8f381
Update apiErrorHandler.js
GarrettEHill Jul 10, 2024
759c4e7
remove unused code
GarrettEHill Jul 10, 2024
fd4efea
adding await
GarrettEHill Jul 10, 2024
3c381be
cleanup
GarrettEHill Jul 11, 2024
de51a81
initial pass
nvms Jul 11, 2024
e8832d1
updates per codereview
GarrettEHill Jul 11, 2024
a17d014
Merge branch 'main' into TTAHUB-3097/worker-transactions
GarrettEHill Jul 11, 2024
5b4dfbf
different call when new vs. not-new
nvms Jul 11, 2024
9ae5d7d
Merge branch 'main' into TTAHUB-3097/worker-transactions
GarrettEHill Jul 11, 2024
aab5350
fix AR tests
nvms Jul 11, 2024
2c10411
fix localStorage tests
nvms Jul 11, 2024
8c2a5e0
don't force programType
nvms Jul 11, 2024
ff8637c
Merge branch 'main' into TTAHUB-3097/worker-transactions
GarrettEHill Jul 11, 2024
3a4202e
Merge branch 'main' into TTAHUB-3078/ssdi
GarrettEHill Jul 11, 2024
fd1a662
endpoint path change
nvms Jul 12, 2024
5e482c9
Update handlers.test.js
GarrettEHill Jul 12, 2024
95772c7
Update ssdi.test.js
GarrettEHill Jul 12, 2024
b0a4dd1
populate regionId on old session report
Jul 12, 2024
e5febbb
clean up temp tables for CI
Jul 12, 2024
a6139fb
pacify linter by removing tab
Jul 12, 2024
b1e6113
Update apiErrorHandler.js
GarrettEHill Jul 12, 2024
0ef613c
update test
nvms Jul 15, 2024
440a55a
put behind read permissions
nvms Jul 15, 2024
c678a4c
update test
nvms Jul 15, 2024
45f3b6e
Merge pull request #2270 from HHS/TTAHUB-3187/fix_old_session_data
hardwarehuman Jul 15, 2024
3a79374
get region id from the report
nvms Jul 15, 2024
7cd85f7
dont pass region id
nvms Jul 15, 2024
98ac36a
Merge pull request #2265 from HHS/jp/3095/dont-remove-expired-grants-…
nvms Jul 15, 2024
be2c339
Merge pull request #2233 from HHS/TTAHUB-3097/worker-transactions
GarrettEHill Jul 15, 2024
a0170be
Remove ObjectiveRoles
kryswisnaskas Jul 16, 2024
fac45de
relocate
GarrettEHill Jul 16, 2024
86d95a0
fix paths
GarrettEHill Jul 16, 2024
a9c13d6
increase from 3 to 4
nvms Jul 16, 2024
5051243
fix paths
GarrettEHill Jul 16, 2024
a9018ff
Merge pull request #2273 from HHS/kw-fix-topics-role-filter
kryswisnaskas Jul 16, 2024
f309f03
Merge pull request #2204 from HHS/TTAHUB-3078/ssdi
GarrettEHill Jul 16, 2024
fa573ab
Merge pull request #2274 from HHS/jp/3104/prod-mem
nvms Jul 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deployment_config/prod_vars.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
env: prod
web_instances: 3
web_memory: 3GB
web_memory: 4GB
worker_instances: 2
worker_memory: 1GB
similarity_api_instances: 1
Expand Down
2 changes: 1 addition & 1 deletion email_templates/changes_requested_by_manager/html.pug
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ style
include ../email.css
p Hello,
p
p #{managerName} requested changed to report #{displayId}.
p #{managerName} requested changes to report #{displayId}.
if comments
p #{managerName} provided the following comments:
blockquote !{comments}
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/fetchers/activityReports.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ export const getRecipients = async (region) => {
return recipients.json();
};

export const getRecipientsForExistingAR = async (reportId) => {
const url = join(activityReportUrl, `${reportId}`, 'activity-recipients');
const recipients = await get(url);
return recipients.json();
};

export const getGoals = async (grantIds) => {
const params = grantIds.map((grantId) => `grantIds=${grantId}`);
const url = join(activityReportUrl, 'goals', `?${params.join('&')}`);
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/pages/ActivityReport/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('ActivityReport', () => {

beforeEach(() => {
fetchMock.get('/api/activity-reports/activity-recipients?region=1', recipients);
fetchMock.get('/api/activity-reports/1/activity-recipients', recipients);
fetchMock.get('/api/activity-reports/groups?region=1', [{
id: 110,
name: 'Group 1',
Expand Down Expand Up @@ -155,6 +156,7 @@ describe('ActivityReport', () => {
};

fetchMock.get('/api/activity-reports/activity-recipients?region=1', groupRecipients, { overwriteRoutes: true });
fetchMock.get('/api/activity-reports/1/activity-recipients', groupRecipients, { overwriteRoutes: true });

const data = formData();
fetchMock.get('/api/activity-reports/1', { ...data, activityRecipients: [] });
Expand Down Expand Up @@ -226,6 +228,7 @@ describe('ActivityReport', () => {
};

fetchMock.get('/api/activity-reports/activity-recipients?region=1', groupRecipients, { overwriteRoutes: true });
fetchMock.get('/api/activity-reports/1/activity-recipients', groupRecipients, { overwriteRoutes: true });

const data = formData();
fetchMock.get('/api/activity-reports/1', { ...data, activityRecipients: [] });
Expand Down Expand Up @@ -363,6 +366,7 @@ describe('ActivityReport', () => {

describe('resetToDraft', () => {
it('navigates to the correct page', async () => {
fetchMock.get('/api/activity-reports/3/activity-recipients', recipients);
const data = formData();
// load the report
fetchMock.get('/api/activity-reports/3', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ describe('Local storage fallbacks', () => {

beforeEach(() => {
fetchMock.get('/api/activity-reports/activity-recipients?region=1', recipients);
fetchMock.get('/api/activity-reports/1/activity-recipients', recipients);
fetchMock.get('/api/activity-reports/groups?region=1', []);
fetchMock.get('/api/users/collaborators?region=1', []);
fetchMock.get('/api/activity-reports/approvers?region=1', []);
Expand Down
13 changes: 11 additions & 2 deletions frontend/src/pages/ActivityReport/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ import {
submitReport,
saveReport,
getReport,
getRecipients,
getRecipientsForExistingAR,
createReport,
getCollaborators,
getApprovers,
reviewReport,
resetToDraft,
getGroupsForActivityReport,
getRecipients,
} from '../../fetchers/activityReports';
import useLocalStorage, { setConnectionActiveWithError } from '../../hooks/useLocalStorage';
import NetworkContext, { isOnlineMode } from '../../NetworkContext';
Expand Down Expand Up @@ -277,8 +278,16 @@ function ActivityReport({
};
}

const getRecips = async () => {
if (reportId.current && reportId.current !== 'new') {
return getRecipientsForExistingAR(reportId.current);
}

return getRecipients(report.regionId);
};

const apiCalls = [
getRecipients(report.regionId),
getRecips(),
getCollaborators(report.regionId),
getApprovers(report.regionId),
getGroupsForActivityReport(report.regionId),
Expand Down
179 changes: 135 additions & 44 deletions src/lib/apiErrorHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,26 @@ import { sequelize } from '../models';
* @returns {Promise<number|null>} - The ID of the stored request error, or null if storing failed.
*/
async function logRequestError(req, operation, error, logContext) {
// Check if error logging should be suppressed
if (
operation !== 'SequelizeError'
&& process.env.SUPPRESS_ERROR_LOGGING
&& process.env.SUPPRESS_ERROR_LOGGING.toLowerCase() === 'true'
) {
return 0;
}
if (!error) {
return 0;
}

try {
// Prepare the response body for storage
const responseBody = typeof error === 'object'
&& error !== null ? { ...error, errorStack: error?.stack } : error;
? { ...error, errorStack: error?.stack }
: error;

// Prepare the request body for storage
const requestBody = {
...(req.body
&& typeof req.body === 'object'
&& Object.keys(req.body).length > 0
&& { body: req.body }),
...(req.params
&& typeof req.params === 'object'
&& Object.keys(req.params).length > 0
&& { params: req.params }),
...(req.query
&& typeof req.query === 'object'
&& Object.keys(req.query).length > 0
&& { query: req.query }),
...(req.body && typeof req.body === 'object' && Object.keys(req.body).length > 0 && { body: req.body }),
...(req.params && typeof req.params === 'object' && Object.keys(req.params).length > 0 && { params: req.params }),
...(req.query && typeof req.query === 'object' && Object.keys(req.query).length > 0 && { query: req.query }),
};

// Create a request error in the database and get its ID
Expand Down Expand Up @@ -69,15 +61,13 @@ async function logRequestError(req, operation, error, logContext) {
* @param {Object} logContext - The context for logging.
*/
export const handleError = async (req, res, error, logContext) => {
// Check if the environment is development
if (process.env.NODE_ENV === 'development') {
logger.error(error);
}

let operation;
let label;

// Check if the error is an instance of Sequelize.Error
if (error instanceof Sequelize.Error) {
operation = 'SequelizeError';
label = 'Sequelize error';
Expand All @@ -86,27 +76,17 @@ export const handleError = async (req, res, error, logContext) => {
label = 'UNEXPECTED ERROR';
}

// eslint-disable-next-line max-len
if (error instanceof Sequelize.ConnectionError || error instanceof Sequelize.ConnectionAcquireTimeoutError) {
if (error instanceof Sequelize.ConnectionError
|| error instanceof Sequelize.ConnectionAcquireTimeoutError) {
const pool = sequelize?.connectionManager?.pool;
const usedConnections = pool ? pool?.used?.length : null;
const waitingConnections = pool ? pool?.pending?.length : null;
const usedConnections = pool ? pool.used.length : null;
const waitingConnections = pool ? pool.pending.length : null;
logger.error(`${logContext.namespace} Connection Pool: Used Connections - ${usedConnections}, Waiting Connections - ${waitingConnections}`);
}

// Log the request error and get the error ID
const requestErrorId = await logRequestError(req, operation, error, logContext);

let errorMessage;
const errorMessage = error?.stack || error;

// Check if the error has a stack property
if (error?.stack) {
errorMessage = error.stack;
} else {
errorMessage = error;
}

// Log the error message with the error ID if available
if (requestErrorId) {
logger.error(`${logContext.namespace} - id: ${requestErrorId} ${label} - ${errorMessage}`);
} else {
Expand All @@ -117,12 +97,11 @@ export const handleError = async (req, res, error, logContext) => {
};

/**
* Handles any unexpected errors in an error handler catch block
*
* @param {*} req - request
* @param {*} res - response
* @param {*} error - error
* @param {*} logContext - useful data for logging
* Handles any unexpected errors in an error handler catch block.
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @param {Error} error - The error object.
* @param {Object} logContext - The context for logging.
*/
export function handleUnexpectedErrorInCatchBlock(req, res, error, logContext) {
logger.error(`${logContext.namespace} - Unexpected error in catch block - ${error}`);
Expand All @@ -131,11 +110,10 @@ export function handleUnexpectedErrorInCatchBlock(req, res, error, logContext) {

/**
* Handles API errors. Saves data in the RequestErrors table and sends 500 error.
*
* @param {*} req - request
* @param {*} res - response
* @param {*} error - error
* @param {*} logContext - useful data for logging
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @param {Error} error - The error object.
* @param {Object} logContext - The context for logging.
*/
export default async function handleErrors(req, res, error, logContext) {
try {
Expand All @@ -144,3 +122,116 @@ export default async function handleErrors(req, res, error, logContext) {
handleUnexpectedErrorInCatchBlock(req, res, e, logContext);
}
}

/**
* Logs a worker error and stores it in the database.
* @param {Object} job - The job object.
* @param {string} operation - The operation name.
* @param {Error} error - The error object.
* @param {Object} logContext - The logging context.
* @returns {Promise<number|null>} - The ID of the stored request error, or null if storing failed.
*/
const logWorkerError = async (job, operation, error, logContext) => {
if (
operation !== 'SequelizeError'
&& process.env.SUPPRESS_ERROR_LOGGING
&& process.env.SUPPRESS_ERROR_LOGGING.toLowerCase() === 'true'
) {
return 0;
}
if (!error) {
return 0;
}

try {
const responseBody = typeof error === 'object'
? { ...error, errorStack: error?.stack }
: error;

const requestBody = {
...(job.data && typeof job.data === 'object' && Object.keys(job.data).length > 0 && { data: job.data }),
};

const requestErrorId = await createRequestError({
operation,
uri: job.queue.name,
method: 'PROCESS_JOB',
requestBody,
responseBody,
responseCode: INTERNAL_SERVER_ERROR,
});

return requestErrorId;
} catch (e) {
logger.error(`${logContext.namespace} - Sequelize error - unable to store RequestError - ${e}`);
}

return null;
};

/**
* Handles errors in a worker job.
* @param {Object} job - The job object.
* @param {Error} error - The error object.
* @param {Object} logContext - The context for logging.
*/
export const handleWorkerError = async (job, error, logContext) => {
if (process.env.NODE_ENV === 'development') {
logger.error(error);
}

let operation;
let label;

if (error instanceof Sequelize.Error) {
operation = 'SequelizeError';
label = 'Sequelize error';
} else {
operation = 'UNEXPECTED_ERROR';
label = 'UNEXPECTED ERROR';
}

if (error instanceof Sequelize.ConnectionError
|| error instanceof Sequelize.ConnectionAcquireTimeoutError) {
const pool = sequelize?.connectionManager?.pool;
const usedConnections = pool ? pool.used.length : null;
const waitingConnections = pool ? pool.pending.length : null;
logger.error(`${logContext.namespace} Connection Pool: Used Connections - ${usedConnections}, Waiting Connections - ${waitingConnections}`);
}

const requestErrorId = await logWorkerError(job, operation, error, logContext);

const errorMessage = error?.stack || error;

if (requestErrorId) {
logger.error(`${logContext.namespace} - id: ${requestErrorId} ${label} - ${errorMessage}`);
} else {
logger.error(`${logContext.namespace} - ${label} - ${errorMessage}`);
}

// Handle job failure as needed
};

/**
* Handles any unexpected errors in a worker error handler catch block.
* @param {Object} job - The job object.
* @param {Error} error - The error object.
* @param {Object} logContext - The context for logging.
*/
export const handleUnexpectedWorkerError = (job, error, logContext) => {
logger.error(`${logContext.namespace} - Unexpected error in catch block - ${error}`);
};

/**
* Handles worker job errors. Logs the error and stores it in the database.
* @param {Object} job - The job object.
* @param {Error} error - The error object.
* @param {Object} logContext - The context for logging.
*/
export const handleWorkerErrors = async (job, error, logContext) => {
try {
await handleWorkerError(job, error, logContext);
} catch (e) {
handleUnexpectedWorkerError(job, e, logContext);
}
};
Loading