Skip to content

Commit 1c8fce5

Browse files
Merge pull request #5 from NYPL/main
Allow reconnecting to PG connection pool
2 parents bb2cb95 + a1ee916 commit 1c8fce5

5 files changed

Lines changed: 48 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v0.0.4 - 2/13
4+
- In PostgreSQLClient, allow reconnecting after `close_connection` has been called
5+
- Updated README with deployment information
6+
37
## v0.0.3 - 2/10
48

59
- Added GitHub Actions workflow for deploying to production

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This package contains common Python utility classes and functions.
88
* Decrypting values with KMS
99
* Encoding and decoding records using a given Avro schema
1010
* Connecting to and querying a MySQL database
11-
* Connecting to and querying a PostgreSQL database
11+
* Connecting to and querying a PostgreSQL database using a connection pool
1212
* Connecting to and querying Redshift
1313

1414
## Functions
@@ -28,4 +28,23 @@ pip install '.[tests]'
2828
deactivate && source testenv/bin/activate
2929
```
3030

31-
Add any new dependencies required by code in the `nypl_py_utils` directory to the `dependencies` section of `pyproject.toml`. Add dependencies only required by code in the `tests` directory to the `[project.optional-dependencies]` section.
31+
Add any new dependencies required by code in the `nypl_py_utils` directory to the `dependencies` section of `pyproject.toml`. Add dependencies only required by code in the `tests` directory to the `[project.optional-dependencies]` section.
32+
33+
## Git workflow
34+
This repo uses the [Main-QA-Production](https://github.com/NYPL/engineering-general/blob/main/standards/git-workflow.md#main-qa-production) git workflow.
35+
36+
[`main`](https://github.com/NYPL/python-utils/tree/main) has the latest and greatest commits, [`qa`](https://github.com/NYPL/python-utils/tree/qa) has what's in our QA environment, and [`production`](https://github.com/NYPL/python-utils/tree/production) has what's in our production environment.
37+
38+
### Ideal Workflow
39+
- Cut a feature branch off of `main`
40+
- Commit changes to your feature branch
41+
- File a pull request against `main` and assign a reviewer (who must be an owner)
42+
- In order for the PR to be accepted, it must pass all unit tests, have no lint issues, and update the CHANGELOG (or contain the `Skip-Changelog` label in GitHub)
43+
- After the PR is accepted, merge into `main`
44+
- Merge `main` > `qa`
45+
- Deploy app to QA on GitHub and confirm it works
46+
- Merge `qa` > `production`
47+
- Deploy app to production on GitHub and confirm it works
48+
49+
## Deployment
50+
The utils repo is deployed as a PyPI package [here](https://pypi.org/project/nypl-py-utils/) and as a Test PyPI package for QA purposes [here](https://test.pypi.org/project/nypl-py-utils/). In order to be deployed, the version listed in `pyproject.toml` **must be updated**. To deploy to Test PyPI, create a new release in GitHub and tag it `qa-vX.X.X`. The GitHub Actions deploy-qa workflow will then build and publish the package. To deploy to production PyPI, create a release and tag it `production-vX.X.X`.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "nypl_py_utils"
7-
version = "0.0.4"
7+
version = "0.0.5"
88
authors = [
99
{ name="Aaron Friedman", email="aaronfriedman@nypl.org" },
1010
]

src/nypl_py_utils/classes/postgresql_client.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ def __init__(self, host, port, db_name, user, password, **kwargs):
1414
self.db_name = db_name
1515
self.timeout = kwargs.get('timeout', 300)
1616

17-
conn_info = 'postgresql://{user}:{password}@{host}:{port}/{db_name}'\
18-
.format(user=user, password=password, host=host, port=port,
19-
db_name=db_name)
17+
self.conn_info = ('postgresql://{user}:{password}@{host}:{port}/'
18+
'{db_name}').format(user=user, password=password,
19+
host=host, port=port,
20+
db_name=db_name)
21+
self.min_size = kwargs.get('min_size', 1)
22+
self.max_size = kwargs.get('max_size', None)
2023
self.pool = ConnectionPool(
21-
conn_info, open=False,
24+
self.conn_info, open=False,
2225
min_size=kwargs.get('min_size', 1),
2326
max_size=kwargs.get('max_size', None))
2427

@@ -29,6 +32,10 @@ def connect(self):
2932
"""
3033
self.logger.info('Connecting to {} database'.format(self.db_name))
3134
try:
35+
if self.pool is None:
36+
self.pool = ConnectionPool(
37+
self.conn_info, open=False, min_size=self.min_size,
38+
max_size=self.max_size)
3239
self.pool.open(wait=True, timeout=self.timeout)
3340
except psycopg.Error as e:
3441
self.logger.error(
@@ -67,6 +74,7 @@ def close_connection(self):
6774
self.logger.debug('Closing {} database connection'.format(
6875
self.db_name))
6976
self.pool.close()
77+
self.pool = None
7078

7179

7280
class PostgreSQLClientError(Exception):

tests/test_postgresql_client.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_init_with_kwargs(self):
3333

3434
def test_connect(self, test_instance):
3535
test_instance.connect()
36-
test_instance.pool.open.assert_called_once()
36+
test_instance.pool.open.assert_called_once_with(wait=True, timeout=300)
3737

3838
def test_connect_with_exception(self):
3939
test_instance = PostgreSQLClient(
@@ -61,4 +61,12 @@ def test_execute_query(self, test_instance, mocker):
6161
def test_close_connection(self, test_instance):
6262
test_instance.connect()
6363
test_instance.close_connection()
64-
test_instance.pool.close.assert_called_once()
64+
assert test_instance.pool is None
65+
66+
def test_reopen_connection(self, test_instance, mocker):
67+
test_instance.connect()
68+
test_instance.close_connection()
69+
test_instance.connect()
70+
test_instance.pool.open.assert_has_calls([
71+
mocker.call(wait=True, timeout=300),
72+
mocker.call(wait=True, timeout=300)])

0 commit comments

Comments
 (0)