-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e536fc0
commit cf4446e
Showing
10 changed files
with
325 additions
and
50 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
const express = require('express'); | ||
|
||
const app = express(); | ||
|
||
// Middleware function to set timeout for all POST requests | ||
const timeoutMiddleware = (req, res, next) => { | ||
const TIMEOUT_DURATION = 1000; | ||
|
||
req.setTimeout(TIMEOUT_DURATION, () => { | ||
// Handle timeout | ||
res.status(408).send('Request Timeout'); | ||
}); | ||
|
||
next(); | ||
}; | ||
|
||
app.post('/_session', (req, res) => { | ||
res.set('Set-Cookie', 'AuthSession=abc123'); | ||
res.status(200).send('OK'); | ||
}); | ||
|
||
app.get('/medic/_design/medic-client/_view/contacts_by_type_freetext', (req, res) => { | ||
const startkey = JSON.parse(req.query.startkey); | ||
console.log('contacts_by_type_freetext', startkey); | ||
const DATA = [ | ||
// eslint-disable-next-line max-len | ||
{ id: 'e847f6e2-6dba-46dd-8128-5b153d0cd75f', key: ['b_sub_county', 'name:malava'], value: 'false false b_sub_county malava', doc: { _id: 'e847f6e2-6dba-46dd-8128-5b153d0cd75f', _rev: '1-cd20b7095c20172237867233b0375eda', parent: { _id: '95d9abd1-7c17-41b1-af98-595509f96631' }, type: 'contact', is_name_generated: 'false', name: 'Malava', external_id: '', contact: { _id: '1e3d8375-6ab4-4409-be3f-3324db7658e9' }, contact_type: 'b_sub_county', reported_date: 1702573623984 } }, | ||
// eslint-disable-next-line max-len | ||
{ id: '2926bf4c-63eb-433d-a2b4-274fd05d2f1c', key: ['c_community_health_unit', 'name:chu'], value: 'false false c_community_health_unit chu', doc: { _id: '2926bf4c-63eb-433d-a2b4-274fd05d2f1c', _rev: '1-c15f26fe064f8357c19d1124286bf4c4', name: 'Chu', PARENT: 'Chepalungu', code: '123456', type: 'contact', contact_type: 'c_community_health_unit', parent: { _id: 'e847f6e2-6dba-46dd-8128-5b153d0cd75f', parent: { _id: '95d9abd1-7c17-41b1-af98-595509f96631' } }, contact: { _id: 'bb9ebc4c6af161ee0f53b42339001fb1' }, reported_date: 1701631255451 } }, | ||
]; | ||
res.json({ | ||
total_rows: 2, | ||
offset: 0, | ||
rows: DATA.filter(r => r.key[0] === startkey[0]) | ||
}); | ||
}); | ||
|
||
app.use(timeoutMiddleware); | ||
|
||
app.all('*', (req, res) => { | ||
setTimeout(() => { | ||
res.status(200).send('OK'); | ||
}, 2000); | ||
}); | ||
|
||
// Start the server | ||
app.listen(3556, () => { | ||
console.log(`Server is listening on port ${3556}`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { AxiosError, AxiosRequestConfig } from 'axios'; | ||
import isRetryAllowed from 'is-retry-allowed'; | ||
import { UserPayload } from '../services/user-payload'; | ||
import { ChtApi } from './cht-api'; | ||
|
||
const RETRY_COUNT = 4; | ||
const RETRYABLE_STATUS_CODES = [500, 502, 503, 504, 511]; | ||
|
||
export const axiosRetryConfig = { | ||
retries: RETRY_COUNT, | ||
retryDelay: () => 1000, | ||
retryCondition: (err: AxiosError) => { | ||
const status = err.response?.status; | ||
return (!status || RETRYABLE_STATUS_CODES.includes(status)) && isRetryAllowed(err); | ||
}, | ||
onRetry: (retryCount: number, error: AxiosError, requestConfig: AxiosRequestConfig) => { | ||
console.log(`${requestConfig.url} failure. Retrying (${retryCount})`); | ||
}, | ||
}; | ||
|
||
export async function retryOnUpdateConflict<T>(funcWithGetAndPut: () => Promise<T>): Promise<T> { | ||
for (let retryCount = 0; retryCount < RETRY_COUNT; retryCount++) { | ||
try { | ||
return await funcWithGetAndPut(); | ||
} catch (err : any) { | ||
const statusCode = err.response?.status; | ||
if (statusCode === 409) { | ||
console.log(`Retrying on update-conflict (${retryCount})`); | ||
continue; | ||
} | ||
|
||
throw err; | ||
} | ||
} | ||
|
||
throw Error('update-conflict 409 persisted'); | ||
} | ||
|
||
export async function createUserWithRetries(userPayload: UserPayload, chtApi: ChtApi): Promise<{ username: string; password: string }> { | ||
for (let retryCount = 0; retryCount < RETRY_COUNT; ++retryCount) { | ||
try { | ||
await chtApi.createUser(userPayload); | ||
return userPayload; | ||
} catch (err: any) { | ||
if (axiosRetryConfig.retryCondition(err)) { | ||
continue; | ||
} | ||
|
||
if (err.response?.status !== 400) { | ||
throw err; | ||
} | ||
|
||
// no idea when/why some instances yield "response.data" as JSON vs some as string | ||
const errorMessage = err.response?.data?.error?.message || err.response?.data; | ||
console.error('createUser retry because', errorMessage); | ||
if (errorMessage.includes('already taken.')) { | ||
userPayload.makeUsernameMoreComplex(); | ||
continue; | ||
} | ||
|
||
const RETRY_PASSWORD_STRINGS = ['The password must be at least', 'The password is too easy to guess.']; | ||
if (RETRY_PASSWORD_STRINGS.find(str => errorMessage.includes(str))) { | ||
userPayload.regeneratePassword(); | ||
continue; | ||
} | ||
|
||
throw err; | ||
} | ||
} | ||
|
||
throw new Error('could not create user ' + userPayload.contact); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.