You can find many articles on the internet on how to deploy a Django project to production for the first time. But, what should you do when your project is already on production, and during deployments, you need to ensure the consistency of related systems and, at the same time, the continuity of your product?
Production is a software and hardware complex that is available to end users. It includes servers, virtual machines, and containers with stable software installed.
There are many requirements for production. However, in this article, we will focus on efficiency and continuity.
Efficiency is a guarantee that the product will do what it is supposed to do.
Continuity is a guarantee of efficient work while using this product.
That is, if a login attempt always returns an error, this is lack of efficiency. But, if a user rarely receives such an error, then this is a violation of continuity.
Several containers, virtual machines, or servers are used on production depending on the architecture.
I do not consider the situation when only one process is working on one server on production since it is similar to the usual development environment.
In general, you most often encounter the scheme with several containers. They are accessed through a balancer. There may be more than one balancer. From containers, one database is accessed, but there may be several databases including sharding and replicas. They can also access brokers like Kafka and other services. Other services can also somehow exchange information with backends.
For example, let us consider only changes to code and a database.
The changes that can be made in code so that this affects a database and vice versa:
You can also add triggers and functions, change the scheme, and many more. However, the general approaches to applying this to production are shown in these very examples.
If you need to add a model (table) to an application locally in the development environment, then you should do the following:
python manage.py makemigrations
.python manage.py migrate
.
But on production, there are many instances of your application, git, and a separate process for running migrations.
You do not often have direct access to Prod. And this is good. For example, the flow might look like this.
In such a scheme, migrations are run first. Then, one by one, pods are restarted.
In such an architecture, there may always be a situation when migrations have been performed, but the code on production has not changed.
Then the pods are being replaced. Some instances have new code, some have the old one.
Moreover, if you perform migrations when pod replacement is completed, a different situation will take place: the code on the server is updated, but the database is not.
Both situations imply some period of time when the database and the code are inconsistent.
Fortunately, Django does not check for consistency. However, the absence of the necessary elements results in exceptions.
They are:
Migration needs to be performed before changing code when this implies:
Migration needs to be performed after changing code when this implies:
Renaming is performed in several steps:
All this seems complicated. But look at the schemes given above. On multi-pod production, during deployment, it always happens that part of the code works with the old database scheme while other part works with the new one. This may result in exceptions.
Thus, the basic algorithms for dealing with Django models do not work when it comes to production. Changes need to be deployed in several steps depending on the code architecture and CI / CD flow used in a particular case.
However, when making changes, you can always be guided by what the code expects when sending requests to the database. Beside standard cases, there may be various exceptions and obstacles that require ingenuity to find a way around.
In the upcoming articles, I will describe in detail some of the cases mentioned here.