Skip to content

Commit

Permalink
rollback a batch on submit if one record encounters an error, display…
Browse files Browse the repository at this point in the history
… an error for the user to indicate things did not work
  • Loading branch information
micheal-w-wells committed Nov 22, 2023
1 parent 708b38b commit d014246
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 71 deletions.
2 changes: 1 addition & 1 deletion api/src/paths/batch/{id}/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ function execBatch(): RequestHandler {
} catch (error) {
defaultLog.error(error);
return res.status(400).json({
message: 'Batch update exec failed',
message: 'Batch update exec failed, error: ' + error.message,
request: req.body,
count: 1,
namespace: 'batch',
Expand Down
138 changes: 74 additions & 64 deletions api/src/utils/batch/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,81 +101,91 @@ export const BatchExecutionService = {
if (statusQueryResult.rowCount !== 1) {
throw new Error('Batch not in executable status');
}
for (const [index, row] of validatedBatchData.rows.entries()) {
let errorRow = false;
if (row.rowValidationResult.find((vr) => !vr.valid)) {
errorRow = true;
} else {
Object.values(row.data).forEach((propertyValue: any) => {
if (
(propertyValue.validationMessages.length > 0 &&
propertyValue.validationMessages.find((vm) => vm.severity === 'error')) ||
row.RowValidationResult
) {
errorRow = true;
}
});
}
if (errorRow && errorRowsBehaviour === 'Skip') continue;

const { id: activityId, shortId, payload, geog } = _mapToDBObject(
row,
desiredFinalStatus,
template.type,
template.subtype,
userInfo
);

let guid = null;
if (userInfo?.idir_userid !== null) {
guid = userInfo?.idir_userid.toLowerCase() + '@idir';
} else if (userInfo?.bceid_userid !== null) {
guid = userInfo?.bceid_userid.toLowerCase() + '@bceid-business';
}
const qc = {
text: `INSERT INTO activity_incoming_data (activity_id, short_id, activity_payload, batch_id, activity_type,

await dbConnection.query('BEGIN;');

try {
for (const [index, row] of validatedBatchData.rows.entries()) {
let errorRow = false;
if (row.rowValidationResult.find((vr) => !vr.valid)) {
errorRow = true;
} else {
Object.values(row.data).forEach((propertyValue: any) => {
if (
(propertyValue.validationMessages.length > 0 &&
propertyValue.validationMessages.find((vm) => vm.severity === 'error')) ||
row.RowValidationResult
) {
errorRow = true;
}
});
}
if (errorRow && errorRowsBehaviour === 'Skip') continue;

const { id: activityId, shortId, payload, geog } = _mapToDBObject(
row,
desiredFinalStatus,
template.type,
template.subtype,
userInfo
);

let guid = null;
if (userInfo?.idir_userid !== null) {
guid = userInfo?.idir_userid.toLowerCase() + '@idir';
} else if (userInfo?.bceid_userid !== null) {
guid = userInfo?.bceid_userid.toLowerCase() + '@bceid-business';
}
const qc = {
text: `INSERT INTO activity_incoming_data (activity_id, short_id, activity_payload, batch_id, activity_type,
activity_subtype, form_status, created_by, updated_by,
created_by_with_guid, updated_by_with_guid, geog, row_number,
species_positive,
species_negative,
species_treated)
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)`,
values: [
activityId,
shortId,
payload,
id,
template.type,
template.subtype,
errorRow ? errorRowsBehaviour : desiredFinalStatus,
userInfo?.preferred_username,
userInfo?.preferred_username,
guid,
guid,
geog,
index,
JSON.stringify(payload['species_positive']),
JSON.stringify(payload['species_negative']),
JSON.stringify(payload['species_treated'])
]
};

defaultLog.debug({
message: 'executing insert for batch',
params: {
qc
}
});
values: [
activityId,
shortId,
payload,
id,
template.type,
template.subtype,
errorRow ? errorRowsBehaviour : desiredFinalStatus,
userInfo?.preferred_username,
userInfo?.preferred_username,
guid,
guid,
geog,
index,
JSON.stringify(payload['species_positive']),
JSON.stringify(payload['species_negative']),
JSON.stringify(payload['species_treated'])
]
};

try {
await dbConnection.query(qc);
} catch (e) {
defaultLog.debug({
message: 'error executing insert for batch error->' + JSON.stringify(e)
message: 'executing insert for batch',
params: {
qc
}
});
throw e;

try {
await dbConnection.query(qc);
} catch (e) {
defaultLog.debug({
message: 'error executing insert for batch error->' + JSON.stringify(e)
});
throw e;
}
}
} catch (e) {
await dbConnection.query('ROLLBACK;');
throw e;
}
await dbConnection.query('COMMIT;');


await dbConnection.query({
text: `UPDATE batch_uploads
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/batch-upload/BatchDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ const BatchGlobalValidationErrors = ({ batch }) => {
};

const BatchDetail = ({ id }) => {
const { working, error, item: batch } = useSelector(selectBatch);
const { working, error, item: batch, errorMessage } = useSelector(selectBatch);
const dispatch = useDispatch();

useEffect(() => {
Expand All @@ -164,7 +164,7 @@ const BatchDetail = ({ id }) => {
return <Spinner />;
}
if (error) {
return <Error />;
return <><Error />{ errorMessage }</>;
}
if (batch == null) {
return <span>No batch found</span>;
Expand Down
1 change: 1 addition & 0 deletions app/src/state/reducers/batch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function createBatchReducer() {
...state,
working: false,
error: true,
errorMessage: `Could not execute batch ${JSON.stringify(action.payload?.message, null, 2)}`,
item: null
};
case BATCH_EXECUTE_REQUEST:
Expand Down
15 changes: 11 additions & 4 deletions app/src/state/sagas/batch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
BATCH_TEMPLATE_DOWNLOAD_REQUEST,
BATCH_TEMPLATE_DOWNLOAD_SUCCESS,
BATCH_TEMPLATE_LIST_REQUEST,
BATCH_TEMPLATE_LIST_SUCCESS, BATCH_UPDATE_REQUEST, BATCH_UPDATE_SUCCESS, BATCH_DELETE_ERROR
BATCH_TEMPLATE_LIST_SUCCESS, BATCH_UPDATE_REQUEST, BATCH_UPDATE_SUCCESS, BATCH_DELETE_ERROR, BATCH_EXECUTE_ERROR
} from '../actions';
import { Http } from '@capacitor-community/http';
import { actions } from 'components/map/LayerPicker/JSON/actions';
Expand Down Expand Up @@ -189,7 +189,7 @@ function* executeBatch(action) {
const { requestHeaders } = yield select(selectAuth);
const { id } = action.payload;

const { data } = yield Http.request({
const {data, status } = yield Http.request({
method: 'POST',
url: configuration.API_BASE + `/api/batch/${id}/execute`,
headers: {
Expand All @@ -202,9 +202,16 @@ function* executeBatch(action) {
}
});

yield put({ type: BATCH_EXECUTE_SUCCESS, payload: data });
yield put({ type: BATCH_RETRIEVE_REQUEST, payload: { id } });

if(!(status < 200 || status > 299))
{
yield put({ type: BATCH_EXECUTE_SUCCESS, payload: data });
yield put({ type: BATCH_RETRIEVE_REQUEST, payload: { id } });
}
else
{
yield put({ type: BATCH_EXECUTE_ERROR, payload: data })
}
};

function* batchSaga() {
Expand Down

0 comments on commit d014246

Please sign in to comment.