|
1 | 1 | # django-postgres-hot-upgrade |
2 | | -Django app that resets django.contrib.postgres caches that stores postgres extensions OIDs |
| 2 | + |
| 3 | +Let Django clear its PostgreSQL extensions OIDs cache, making it possible to update |
| 4 | +the PostgreSQL version to a new major version on the fly. |
| 5 | + |
| 6 | +## The how |
| 7 | +```console |
| 8 | +$ pip install django-postgres-hot-upgrade |
| 9 | +``` |
| 10 | +```python |
| 11 | +INSTALLED_APPS = [ |
| 12 | + ..., |
| 13 | + # Warning: django_postgres_hot_upgrade requires to be placed before |
| 14 | + # django.contrib.postgres otherwise it will not work. |
| 15 | + 'django_postgres_hot_upgrade', |
| 16 | + 'django.contrib.postgres', |
| 17 | + ..., |
| 18 | +] |
| 19 | +``` |
| 20 | + |
| 21 | +## The why |
| 22 | + |
| 23 | +PostgreSQL keeps internal ids of for various objects |
| 24 | +([OIDs](https://www.postgresql.org/docs/current/datatype-oid.html)). This includes |
| 25 | +loaded extentions. In order to interact with those extensions, Django needs to know |
| 26 | +these IODs, so it loads them and, in order to avoid [unneeded |
| 27 | +requests](https://code.djangoproject.com/ticket/28334?), it caches them in memory for |
| 28 | +the duration of the process. |
| 29 | + |
| 30 | +Several PostgreSQL servers running the same version of PostgreSQL will have consistent |
| 31 | +OIDs but when you upgrade, OIDs can change. If one uses a PostgreSQL load balancer such |
| 32 | +as [pgbouncer](https://www.pgbouncer.org/) or [pgpool](https://www.pgpool.net), one |
| 33 | +could be tempted to migrate between major PostgreSQL versions on the fly, avoinding |
| 34 | +downtime. Indeed, for sufficiently recent versions of PostgreSQL, this would work, apart |
| 35 | +from the OID problem: if OIDs change, Django needs to update its cache. |
| 36 | + |
| 37 | +`django_postgres_hot_upgrade` memorizes the postgres version of the server after each |
| 38 | +connection. When the version is updated, it clears the internal Django OIDs cache, |
| 39 | +forcing Django to fetch the new values. |
| 40 | + |
| 41 | + |
| 42 | +## The rest |
| 43 | + |
| 44 | +**Compatibility**: Please refer to versions of Python and Django tested in |
| 45 | +[tox.ini](tox.ini). |
| 46 | + |
| 47 | +**License**: [MIT](LICENSE) |
| 48 | + |
| 49 | +**Code of Conduct**: This project is placed under the [Contributor |
| 50 | +Coveneant](https://www.contributor-covenant.org/version/2/0/code_of_conduct/). Please |
| 51 | +report any abuse to `joachim.jablon at people-doc.com`. |
| 52 | + |
| 53 | + |
| 54 | +## [Maintainers] The ugly part |
| 55 | + |
| 56 | +Apart from its unit tests, this package has an integration test. In order to test the |
| 57 | +feature, we need to simulate a change of OIDs caused by a live update from PG10 to PG12 |
| 58 | +in a controlled CI environment. This is the most fragile part of the lib, and the most |
| 59 | +likely to break in the future. Here's what you need to know: |
| 60 | + |
| 61 | +- `docker-compose.yml` define two databases `postgres10` and `postgres12` listening on |
| 62 | + 5432 and 5433 respectively. |
| 63 | +- `tests/django_settings.py` define a `default` database using libpq envvars. Note that |
| 64 | + in the settings, we requests the tests to run on the normal database instead of |
| 65 | + dedicated `test_<foo>` database. |
| 66 | +- The OIDs are created by Postgres when installing the extensions. This happens in |
| 67 | + `tests/migrations/0001_initial.py`. The `DJANGO_REVERSE_OPERATIONS` env var controls |
| 68 | + the order of the 2 extensions creation. Running the PG10 migration in normal order |
| 69 | + and the PG12 migration in reverse order ensures the OIDs will be different. |
| 70 | +- The `runtests` script ensure the migrations run on both databases in the decided |
| 71 | + order, then launches the test. Without this, the integration test would likely fail |
| 72 | + because the OIDs would be the same in the two databases. |
| 73 | +- `tox` calls `runtests`. |
| 74 | +- GitHub Actions call `tox`. |
| 75 | + |
| 76 | +The following work to launch tests locally: |
| 77 | + |
| 78 | +- run `tox` or `runtests` on fresh databases |
| 79 | +- run `pytests` if you know the OIDs are already properly set on the 2 databases |
0 commit comments