Skip to content

Commit

Permalink
chore: documentation and startup scripts (#71)
Browse files Browse the repository at this point in the history
* fix: remove rethrow

* chore: add init.db for docker startup

* Add docs for postgres

* chore: add env var docs

* chore: add troubleshooting guide, add monitorStateIntervalInSeconds

* chore: switch to using  /notarial db

* chore: add dotenv and make notify api key non-required docker compose env var

* fix: URLs and refer to jobs on this project
  • Loading branch information
jenbutongit authored Apr 5, 2024
1 parent 6872136 commit 29c485b
Show file tree
Hide file tree
Showing 15 changed files with 391 additions and 75 deletions.
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ This ia a monorepo used for the notarial services apis, which power the [prove y


## Workspaces
Currently, there is only workspace in this project:

* [api](./api/README.md)
* [worker](./worker/README.md)

### Getting started with Docker
You may use docker and docker compose to build and start the project with the right components (e.g. database, microservices), but will not be able to run the application(s) in dev mode.
Expand All @@ -30,12 +30,43 @@ docker compose down
docker compose -d --build
```

### Running the applications locally (without docker)

You may still need docker to start the databases.

From the root directory,
`docker compose up postgres`

This will start the postgres container running on port 5432; with username `user` and password `root`,
and a database created called `notarial` (`postgres://user:root@localhost:5432/notarial`).
[`init.sql`](init.sql) is also loaded as a volume into the container, and will create a database named `queue`
(`postgres://user:root@localhost:5432/queue`). This is useful if you are going to be running [forms-worker](https://github.com/UKForeignOffice/forms-queue)
at the same time. If you are running postgres from this repo, you do not need to run it in `forms-queue`.


1. If you wish to send emails locally, you will need to authenticate your terminal with AWS. (`formsawsauth prod`)
2. Start the api `yarn api start:local`
3. start the worker `NOTIFY_API_KEY=".." yarn worker start:local`
4. Send a post request to `http://localhost:9000/forms`, use the payload found in `notarial-api/api/src/middlewares/services/UserService/personalisation/__tests__/fixtures/testData.ts`, or run the form runner locally, with the webhook configured to `http://localhost:9000/forms`.


### Formatting
This project uses ESLint and Prettier to ensure consistent formatting. It is recommended that you add and turn on the prettier plugin for your IDE, and reformat on save.


## CI/CD
There is a CI/CD pipeline currently set up for deploying new versions of the project to test environments. For more information, please refer to the [CI/CD docs](https://github.com/UKForeignOffice/notarial-api/blob/main/docs/ci.md)
There is a CI/CD pipeline currently set up for deploying new versions of the project to test environments. For more information, please refer to the [CI/CD docs](docs/ci.md)

This project uses [semantic-release](https://github.com/semantic-release/semantic-release). This allows for automatic versioning of the project based on the commit messages when merging.

When merging, prefix the pull request subject with
- `chore:` for changes which should not increment the version number (like documentation changes)
- `fix:` for bug fixes, (increments the patch version)
- `feat:` for new features (increment the minor version)
- `BREAKING:` for major changes (increments the major version)

[Releases](https://github.com/UKForeignOffice/notarial-api/releases) are automatically generated from commit messages. Prefix each commit with one of the above prefixes to include the commit message in the generated message.


## Testing
Currently, there is unit testing and integration testing set up for the api workspace. For more information, refer to the [testing docs](./docs/testing.md).
Expand Down
151 changes: 151 additions & 0 deletions TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Troubleshooting

Use this guide to troubleshoot issues and resolve errors that may occur when notarial-api or notarial-worker is deployed.

Connect to the database:
```sh
kubectl run -it --rm --env PGPASSWORD='<PASSWORD>' --env PAGER= --image=postgres:16 --restart=Never postgres-client -- psql -h <ENDPOINT_URL> -U master -d notarial
```

Replace PASSWORD with the password for the database, ENDPOINT_URL with the endpoint URL for the database.

## pgboss

[pgboss](https://github.com/timgit/pg-boss) is used to manage queueing jobs. On application start, pgboss will automatically create necessary tables in the database.

### Jobs table
The jobs table `pgboss.job` is where all the current jobs are stored. Jobs will remain here, until they are completed or failed. Then they will move to `pgboss.archive`

The jobs table has the following columns:

```
Column | Type | Collation | Nullable | Default
--------------+-----------------------------+-----------+----------+-----------------------------
id | uuid | | not null | gen_random_uuid()
name | text | | not null |
priority | integer | | not null | 0
data | jsonb | | |
state | pgboss.job_state | | not null | 'created'::pgboss.job_state
retrylimit | integer | | not null | 0
retrycount | integer | | not null | 0
retrydelay | integer | | not null | 0
retrybackoff | boolean | | not null | false
startafter | timestamp with time zone | | not null | now()
startedon | timestamp with time zone | | |
singletonkey | text | | |
singletonon | timestamp without time zone | | |
expirein | interval | | not null | '00:15:00'::interval
createdon | timestamp with time zone | | not null | now()
completedon | timestamp with time zone | | |
keepuntil | timestamp with time zone | | not null | now() + '14 days'::interval
on_complete | boolean | | not null | false
output | jsonb | | |
```

Columns/values to note are
- `name`: the name of the job. It can be one of SES_PROCESS, NOTIFY_PROCESS, SES_SEND, NOTIFY_SEND. More detail can be found in [worker/src/README.md](worker/src/README.md). PgBoss will also create some of its own.
- `state`: the state of the job. Read more about them in [pgboss documentation](https://github.com/timgit/pg-boss/blob/master/docs/readme.md#job-states)
- `created`: the job has been created
- `failed`: the job has failed
- `completed`: the job has been completed (successfully)
- `active`: the job is currently being processed
- `data`: the data associated with the job.
- `output`: the output of the job. This will contain the reference number, or the error message if the job has failed
- `keepuntil`: the time until the job will be kept in the table. After this time, the job will be moved to `pgboss.archive`. If you need more time to resolve the issue, you can update this value to a later time.



## Finding jobs
To find jobs that have failed, run the following query:

```postgresql
select id, output from pgboss.job where state = 'failed';
```

## Fixing data
If the retrylimit has not been hit (retrylimit > retrycount) and the retrylimit is not 0, the job will be automatically retried.

It is recommended you run every query in a transaction, so that you can abort the changes if they are incorrect.

```postgresql
begin;
-- First run a query to print the current state of the job you are trying to change
select data from pgboss.job where id = '<id>';
update pgboss.job
set state = 'created',
completedon = null,
retrycount = 0,
state = 'created'
where id = '<id>';
-- Run the query again, to see if you've made the correct changes
select data from pgboss.job where state = 'failed' and id = '<id>';
-- Run the following query to commit the changes
-- commit;
-- Run the following to abort the changes
-- rollback;
```

The following queries will assume that you are running them in a transaction.

## Incorrect data
If the data is incorrect, you can update the data in the database. All data is stored as jsonb, so you can use [postgresql's jsonb functions](https://www.postgresql.org/docs/current/functions-json.html) to update the data

```postgresql
update pgboss.job
set data = jsonb_set(
data,
'{data, keyToChange}',
'"<NEW_ANSWER>"'
)
where id = '<id>';
```

You may find it easier to copy the data to a text editor, make the changes, and then update the data in the database.

```postgresql
update pgboss.job
set data = '<NEW_DATA>'
where id = '<id>';
```

### Retry a job
If a job has failed, and you want to retry it, you can update the job to `created` state, and reset the `retrycount` to 0.

```postgresql
update pgboss.job
set state = 'created',
completedon = null,
retrycount = 0,
state = 'created'
-- output = null
where id = '<id>';
```
You may also want to update output to null, to clear the error message.

## Creating a new job
If the job does not seem to be retrying, or it is easier to just create a new job you need to create a new job, you can do so by running the following query:

```postgresql
insert into pgboss.job (name, data)
values ('NOTIFY_PROCESS', '{"answers": {}, "metadata": {}, "reference": "123456"}');
```

Alternatively, you can copy the data from the failed job, and create a new job with the same data.

```postgresql
insert into pgboss.job (name, data)
SELECT name, data
from pgboss.job where id = '<id>';
```

### Moving a job from archive to job
If a job has been moved to the archive, and you want to retry it, you can move it back to the jobs table.

```postgresql
insert into pgboss.job (name, data)
SELECT name, data
from pgboss.archive where id = '<id>';
```
52 changes: 48 additions & 4 deletions api/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# API workspace
This workspace is used to run the API server, which is called at various parts during the form and triggers email submissions after the form has been submitter.
This workspace is used to run the API server, which is called at various parts during the form and triggers email submissions after the form has been submitted.

Use the API to house all the business logic. This will allow the worker to be a simple service that just listens for messages and sends them to an API.
The API should parse user's data, render email templates etc.

## Prerequisites
1. A node version manager, like [nvm](https://formulae.brew.sh/formula/nvm), or [n](https://github.com/tj/n)
Expand All @@ -19,7 +22,7 @@ yarn install
yarn api build
yarn api start:local
```
These commands will build the project dependencies, cmpile the initial build of the api workspace, and run the workspace in local mode (allowing watching for changes).
These commands will build the project dependencies, compile the initial build of the api workspace, and run the workspace in local mode (allowing watching for changes).

### Getting started with Docker
You may use docker and docker compose to build and start the project with the right components (e.g. database, microservices), but will not be able to run the application(s) in dev mode.
Expand All @@ -41,5 +44,46 @@ docker compose -d --build
This will cause docker to tear down the current container, and force a new build image for the server, allowing you to test your most recent changes.

## Routes
There is currently one route set up, which will be used to test the Optical Character Recognition (OCR) capabilities of the server. This route is:
* /ocr-email

### POST `/forms`
This route is used to submit a form. It will then create two new jobs, "SES_PROCESS" and "NOTIFY_PROCESS". It will then return with a reference number.
The reference number is the GOV.UK Pay reference number. If a GOV.UK pay reference number could not be found, it will generate a random one. Use this reference number to track the user across the application.


### POST `/forms/emails/ses`
This route is used to parse user's data and prepare an email that will be sent to FCDO. The request will come from the SES_PROCESS job.
It will generate an email body to be sent via SES. The attachments are not added to the email body at this point.


### POST `/forms/emails/notify`
This route is used to parse the user's data to generate the confirmation email for the user. The request will come from the NOTIFY_PROCESS job.



### Environment variables

| Env var | Description | default |
|-----------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|
| `PORT` | Port to start the application on | 9000 |
| `NODE_ENV` | Environment the application is running in. If the environment has a matching [config](./config) file, it will use those as the defaults | development |
| `NOTIFY_TEMPLATE_AFFIRMATION_USER_CONFIRMATION` | Notify template which sends a confirmation email to the user for the /affirmation form | 7 |
| `NOTIFY_TEMPLATE_EXCHANGE_USER_CONFIRMATION` | Notify template which sends a confirmation email to the user for the /exchange-uk-cni form | |
| `NOTIFY_TEMPLATE_EXCHANGE_USER_POSTAL_CONFIRMATION` | Notify template which sends a confirmation email to the user for the /cni | |
| `NOTIFY_TEMPLATE_POST_NOTIFICATION` | Notify template which alerts embassies that they have an application | |
| `QUEUE_URL` | The connection string to the database, including username and password | postgres://user:root@localhost:5432/notarial |
| `ARCHIVE_FAILED_AFTER_DAYS` | How long to keep failed jobs in the pgboss.job before moving it to pgboss.archive | 30 |
| `DELETE_ARCHIVED_AFTER_DAYS` | How long to keep jobs in pgboss.archive before deleting it | 7 |
| `SES_SEND_RETRY_BACKOFF` | Whether or not to retry SES_SEND jobs if they failed with exponential backoff (i.e. each retry is delayed longer than the last attempt) | true |
| `SES_SEND_RETRY_LIMIT` | Number of times the SES_SEND job is allowed to be retried | 50 |
| `SES_SEND_ON_COMPLETE` | If SES_SEND has a completion handler (i.e. a job that should be triggered if this job becomes completed), and should be turned on | true |
| `SES_PROCESS_RETRY_BACKOFF` | Whether or not to retry SES_PROCESS if they failed with exponential backoff (i.e. each retry is delayed longer than the last attempt) | true |
| `SES_PROCESS_RETRY_LIMIT` | Number of times the SES_PROCESS job is allowed to be retried | 50 |
| `SES_PROCESS_ON_COMPLETE` | If SES_PROCESS has a completion handler (i.e. a job that should be triggered if this job becomes completed), and should be turned on | true |
| `NOTIFY_SEND_RETRY_BACKOFF` | Whether or not to retry NOTIFY_SEND jobs if they failed with exponential backoff (i.e. each retry is delayed longer than the last attempt) | true |
| `NOTIFY_SEND_RETRY_LIMIT` | Number of times the NOTIFY_SEND job is allowed to be retried | 50 |
| `NOTIFY_SEND_ON_COMPLETE` | If NOTIFY_SENd has a completion handler (i.e. a job that should be triggered if this job becomes completed) | true |
| `NOTIFY_PROCESS_RETRY_BACKOFF` | Whether or not to retry NOTIFY_PROCESS jobs if they failed with exponential backoff (i.e. each retry is delayed longer than the last attempt) | true |
| `NOTIFY_PROCESS_RETRY_LIMIT` | Number of times the NOTIFY_PROCESS job is allowed to be retried | 50 |
| `NOTIFY_PRCESS_ON_COMPLETE` | If the NOTIFY_PROCESS job has a completion handler (i.e. a job that should be triggered if this job becomes completed), and should be turned on | true |


9 changes: 0 additions & 9 deletions api/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
{
"port": "PORT",
"env": "NODE_ENV",
"documentPassword": "DOCUMENT_PASSWORD",
"affirmationTemplate": "AFFIRMATION_TEMPLATE_ID",
"cniTemplate": "CNI_TEMPLATE_ID",
"submissionEmail": "SUBMISSION_EMAIL_ADDRESS",
"senderEmail": "SENDER_EMAIL_ADDRESS",
"Notify": {
"Template": {
"affirmationUserConfirmation": "NOTIFY_TEMPLATE_AFFIRMATION_USER_CONFIRMATION",
"cniUserConfirmation": "NOTIFY_TEMPLATE_CNI_USER_CONFIRMATION",
"exchangeUserConfirmation": "NOTIFY_TEMPLATE_EXCHANGE_USER_CONFIRMATION",
"exchangeUserPostalConfirmation": "NOTIFY_TEMPLATE_EXCHANGE_USER_POSTAL_CONFIRMATION",
"postNotification": "NOTIFY_TEMPLATE_POST_NOTIFICATION"
},
"Retry": {
"backoff": "NOTIFY_RETRY_BACKOFF",
"limit": "NOTIFY_RETRY_LIMIT"
}
},
"Queue": {
Expand Down
3 changes: 1 addition & 2 deletions api/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ if (process.env.NODE_ENV !== "test") {
module.exports = {
port: "9000",
env: "development",
documentPassword: "Sup3rS3cr3tP4ssw0rd",
submissionAddress: "[email protected]",
senderEmail: "[email protected]",
Queue: {
url: "postgresql://user:root@localhost:5432/queue",
url: "postgresql://user:root@localhost:5432/notarial",
defaultOptions: {
retryBackoff: "true",
retryLimit: "50",
Expand Down
Loading

0 comments on commit 29c485b

Please sign in to comment.