Skip to content

Commit aae1452

Browse files
committed
Doc: Add postgresql configuration tutorial in linode
1 parent c60338a commit aae1452

File tree

2 files changed

+441
-16
lines changed

2 files changed

+441
-16
lines changed

cron_jobs_in_flask.md

+16-16
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Config(object):
4242

4343
My configurations above utilize Twilio's SendGrid API to work with emails, especially on a production server. It still works locally though. If you are not familiar with Twilio SendGrid, check out [this tutorial](/twilio_sendgrid/00_overview.md) to learn more. Alternatively, you can use Google's `smtp` for this. Learn how to work with Google's `smtp` [here](email_support_in_flask.md).
4444

45-
Since these variables are sourced from the environemnt, it is best practice to add them in a secret `.env` file which should never be committed to version control.
45+
Since these variables are sourced from the environment, it is best practice to add them in a secret `.env` file which should never be committed to version control.
4646

4747
```python
4848
# .env
@@ -111,9 +111,9 @@ class Client(db.Model):
111111

112112
The model has an additional column called `num_newsletter` whose integer values will be used to determine if a user has received an email newsletter or not. Additionally, this column will be used to determine what email newsletter needs to be sent out.
113113

114-
It is good practice to respect user's contact information. The fact that a user has shared an email address with us does not give the opportunity to spam them. Hence, if a user wishes to opt out of the subscription, they can do so. The application will remember their subscription state using the value in `active` column.
114+
It is good practice to respect users' contact information. The fact that a user has shared an email address with us does not give us the opportunity to spam them. Hence, if a user wishes to opt-out of the subscription, they can do so. The application will remember their subscription state using the value in `active` column.
115115

116-
### Email template
116+
### Email Template
117117

118118
Here is a sample method used to send out an email.
119119

@@ -144,7 +144,7 @@ def send_week1newsletter(client_email, client_username):
144144
client_username=client_username))
145145
```
146146

147-
The `send_week1_newsletter()` function uses both text and HTML content to send out the email. This is similar to the `render_template()` function from flask. It is always advisable to have the text template in the event the email server does not entirely parse the HTML content or there is an unexpected issue.
147+
The `send_week1_newsletter()` function uses both text and HTML content to send out the email. This is similar to the `render_template()` function from the flask. It is always advisable to have the text template in the event the email server does not entirely parse the HTML content or there is an unexpected issue.
148148

149149

150150
### Sending An Email
@@ -193,7 +193,7 @@ def week2_newsletter():
193193
db.session.commit()
194194
```
195195

196-
Notice that the two functions begin by checking of a user is still subscribed to receive emails. The starting value to know what email needs to be sent out is 0. This value is added to the database when the user is being registered.
196+
Notice that the two functions begin by checking of a user is still subscribed to receive emails. The starting value to know what email needs to be sent out is 0. This value is added to the database when the user is registered.
197197

198198
```python
199199
if form.validate_on_submit():
@@ -202,19 +202,19 @@ if form.validate_on_submit():
202202
db.session.commit()
203203
```
204204

205-
0 means that this user is newly registered. If so, then week 1 email newsletter will be sent out to them. As soon as this email is sent out, their status changes to 1, meaning, they should not receive any week 1 newsletter. They are now qualified to receive week 2 newsletter.
205+
0 means that this user is newly registered. If so, then the week 1 email newsletter will be sent out to them. As soon as this email is sent out, their status changes to 1, meaning, they should not receive any week 1 newsletter. They are now qualified to receive the week 2 newsletter.
206206

207207

208208
## Application Context
209209

210-
You have probably come across the command `flask shell`. "Shell" is a command from flask. There is also `flask run` which is used to start the flask server. And many more. It is also possible to create custom commandline operations that suite our needs.
210+
You have probably come across the command `flask shell`. "Shell" is a command from flask. There is also `flask run` which is used to start the flask server. And many more. It is also possible to create custom command-line operations that suit our needs.
211211

212-
In the context of sending periodic email newsletters, we are going to create a command which will run in the application's context such that every time it is invoked, not only will it send out an email, but it will also allow for access to the application's resources such as the database, which me mostly need here.
212+
In the context of sending periodic email newsletters, we are going to create a command which will run in the application's context such that every time it is invoked, not only will it send out an email, but it will also allow for access to the application's resources such as the database, which we most need here.
213213

214214

215215
### Create a Custom Command
216216

217-
Following the principle of separation of concerns, a new module called `cli` will define all that we need for our commandline operations.
217+
Following the principle of separation of concerns, a new module called `cli` will define all that we need for our command-line operations.
218218

219219
```python
220220
# app/cli.py
@@ -244,7 +244,7 @@ def register(app):
244244
print(str(datetime.utcnow()), 'Week 2 emails sent to all subscribed clients\n\n')
245245
```
246246

247-
Flask uses [Click](https://click.palletsprojects.com/) for all commandline operations. In the example above, I have created a root command called `send-newsletter-email` from whom subcommands are derived. These sub-commands are created via `app.cli.group` decorator. All that the subcommands do is to invoke the necessary functions used to send out an email. To ensure that I know when the emails were sent out, I have added a `print()` statement.
247+
Flask uses [Click](https://click.palletsprojects.com/) for all command-line operations. In the example above, I have created a root command called `send-newsletter-email` from whom subcommands are derived. These sub-commands are created via the `app.cli.group` decorator. All that the subcommands do is invoke the necessary functions used to send out an email. To ensure that I know when the emails were sent out, I have added a `print()` statement.
248248

249249

250250
### Test Access to Custom Commands
@@ -310,7 +310,7 @@ Once the job is written and tested, we can now implement the scheduling part. He
310310

311311
Here, I am running the `crontab` command under my computer's user, who is typically the same user that runs the flask application. This ensures that the task runs with the correct permissions. It is advisable to not run this command as a root user.
312312

313-
Once the file is opened, you will notice that it comes with commented out instructions. These instructions offer guidance on how to go about scheduling a task.
313+
Once the file is opened, you will notice that it comes with commented-out instructions. These instructions offer guidance on how to go about scheduling a task.
314314

315315
```python
316316
# ┌───────────── minute (0 - 59)
@@ -324,7 +324,7 @@ Once the file is opened, you will notice that it comes with commented out instru
324324
# * * * * * <command to execute>
325325
```
326326

327-
Each line in a crontab file represents a job in the syntax `* * * * * <command to execute>`. There are five fields which represent the time to execute a command, followed by a shell command itself.
327+
Each line in a crontab file represents a job in the syntax `* * * * * <command to execute>`. There are five fields that represent the time to execute a command, followed by a shell command itself.
328328

329329

330330
### Understanding A Cron Expression
@@ -339,16 +339,16 @@ In our case, we want to run `flask send-newsletter-email week1`. As a command li
339339

340340
- **Current directory**: We need to `cd` into the project's specific directory in the cronjob, by specifying its absolute path.
341341
- **Environment variables**: Flask uses the `.env` and the `.flaskenv` files to automatically access an application's environment variables
342-
- **Virtual environment**: Because it is a flask command, it is best to activate a virtual envronment in the process, or else, run a Python executable located inside the virtualenv directory.
343-
- **Logging**: It is best to ensure that by sending the output to a logfile.
342+
- **Virtual environment**: Because it is a flask command, it is best to activate a virtual environment in the process, or else, run a Python executable located inside the virtualenv directory.
343+
- **Logging**: It is best to ensure that by sending the output to a log file.
344344

345345
To configure the `flask send-newsletter-email week1` command as a cron service, I can schedule week 1 emails to be sent out once every minute as follows:
346346

347347
```python
348348
* * * * * cd /home/harry/newsletter_app && venv/bin/flask send-newsletter-email week1 >> logs/scheduled_email.log 2>&1
349349
```
350350

351-
I have used `&&` to include multiple commands in a single line. I have began by navigating into the directory containing the project. Instead of activating a virtual environment, I decided to locate the `flask` command inside the `venv/bin/` subdirectory which achieves the same effect as activating the environment.
351+
I have used `&&` to include multiple commands in a single line. I began by navigating into the directory containing the project. Instead of activating a virtual environment, I decided to locate the `flask` command inside the `venv/bin/` subdirectory which achieves the same effect as activating the environment.
352352

353353
The `flask` command is immediately followed by my custom CLI commands. As soon as that is executed, the output is redirected and appended to the file `scheduled_email.log` for logging purposes. This helps to know if the job was done successfully or if there was an error. Otherwise, it would be very difficult to know what happened, especially in the event there is an unexpected error.
354354

@@ -365,7 +365,7 @@ Once this job is executed, there will be a new file inside the `logs` sub-folder
365365
| 5 4 * * * command | Run the command daily at 4.05 am |
366366
| 5 16 * * * command | Run the command daily at 4.05 pm |
367367
| 5 4 * * 2 command | Run the command every Tuesday at 4.05 am |
368-
| 5 4 * * 1-5 command | Run the command every weekday at 4.05 am except the weekends |
368+
| 5 4 * * 1-5 command | Run the command every weekday at 4.05 am except the weekends |
369369
| 0-59/2 * * * command | Run the command daily every even minute of the hour |
370370
| 1-59/2 * * * command | Run the command daily every odd minute of the hour |
371371

0 commit comments

Comments
 (0)