How to automatically deploy Python web application

Recently I saw a question from a Python fellow, how to deploy Django application without manually SSH to server and run commands. This style is single-server deployment, where you put all components, from the application code, database, to static, media files, in the same server. No Docker involves. With this deployment strategy, we will need some way to deliver new version of our app everytime new code is pushed to the "release" branch of Git repository. Here is a guide.

Why we need automation? Because it is boring to do these things by hand again and again:

  • SSH to the server, cd to the installation folder.
  • Run git pull.
  • Run commands to stop your services.
...

So sánh hệ thống kiểu của Python và TypeScript

Với hơn một nửa công việc hàng ngày là làm web, Python và JavaScript là hai ngôn ngữ mình dùng nhiều. Đây vốn là hai ngôn ngữ "kiểu động" (dynamic type), nhưng mình vẫn tận dụng hệ thống kiểu (type system) của chúng để viết như với một ngôn ngữ "kiểu tĩnh" (static type). Sau một thời gian thì mình rút ra được một số kinh nghiệm để làm việc với hai hệ này.

Thật ra, ngôn ngữ JavaScript không có ký hiệu kiểu, nên nói chính xác hơn là mình đang dùng TypeScript chứ không phải JavaScript. Trước hết, người đã làm quen với JavaScript mà được giới thiệu về TypeScript thì sẽ bật lên một câu hỏi, tại sao chúng là ngôn ngữ dynamic type thì lại mất công viết như static type làm gì. Đó là vì những ích lợi sau:

  • Giúp các công cụ kiểm tra (static analysis) như MyPy, tsc hiểu được code mình, để phát hiện được bug tiềm tàng trong những trường hợp ngách mà mình chưa test.
  • Giúp các trình soạn thảo (code editor, IDE) hiểu được biến đang có kiểu gì, để đưa ra gợi ý autocomplete đúng hơn.
...

Truy xuất mảng trong JavaScript một cách an toàn

Gần đây mới biết rằng trong JavaScript, khi truy xuất một phần tử trong mảng sau khi kiểm tra trước độ dài của mảng, thì vẫn không đảm bảo được rằng phần tử đó tồn tại.

Ví dụ trong đoạn code 1, biến "first" tại dòng 3 có thể bị undefined, dẫn đến "tz" tại dòng 4 cũng bị undefined theo. Lý do là mảng trong JS là mảng thưa, cho phép các vị trí phần tử không liên tục. Tức là có thể có phần tử ở vị trí 1 mà không có ở vị trí 0.

function useFirst(items: Date[]) {
  if (items.length) {
...

Thư viện ghi log cho ứng dụng Python

Trong quá trình phát triển phần mềm, ghi log là một hoạt động quan trọng phục vụ cho người lập trình. Khi một chương trình chạy không như mong muốn, ta cần phải biết sai chỗ nào để sửa. "Ghi log" là bắt chương trình của ta "kể lại" diễn biến hoạt động của nó, giá trị của một vài biến lúc ấy, để giúp ta kiểm tra lại được chỗ nào sai.

Vậy mình thường dùng thư viện nào cho việc ghi log?

Như đã đề cập trong bài "Khởi đầu dự án Python như thế nào để thuận tiện phát triển lên", Python có một thư viện chuẩn logging, mà điểm lợi là khi các thư viện cùng dùng nó, ta có thể từ tầng ứng dụng điều chỉnh "log level" cho tầng thư viện mà không cần can thiệp vào code của thư viện ấy. Vì lẽ đó, đương nhiên các ứng dụng của mình cũng dùng logging nhưng cũng kèm thêm một số thư viện bổ trợ khác để thỏa mãn nhu cầu / sở thích cá nhân.

Một trong những nhu cầu của mình là cần màu sắc phân biệt, để truy tìm điểm cần tìm cho dễ, ít nhất là các log level cần có màu sắc khác nhau để dễ dàng lọc lựa, bỏ qua thông điệp ít quan trọng. Về khoản màu sắc thì mình ưa dùng thư viện rich. Nó thậm chí còn hơn cả mong đợi vì nó còn nhận diện và tô màu theo "kiểu dữ liệu", ví dụ dữ liệu số có màu khác, dữ liệu chuỗi, đối tượng... có màu khác.

...


Làm việc từ xa bằng máy tính ở nhà

Mình là người hay làm việc bên ngoài văn phòng, cụ thể là quán cafe hay trên đường đi du lịch. Thế nhưng laptop thì không mạnh bằng máy bàn nên mình vẫn thực sự dùng máy tính bàn ở nhà cho công việc, dù đang dùng màn hình và bàn phím của laptop. Vậy mình làm thế nào?

Dù làm về lập trình và có thâm niên nhưng mình vẫn chỉ sử dụng máy móc bình dân. Cụ thể laptop của mình chỉ là Dell Vostro 5568 với CPU Core i5 (2 nhân 4 luồng).

Laptop

Trong thời gian bị phong tỏa vì CoVid, mình cứ băn khoăn lỡ laptop này bị hư thì làm sao đi sửa để tiếp tục làm việc được, nên sau khi được mở cửa lại, mình cũng mua luôn một máy bàn để dự phòng, lỡ bị phong tỏa nữa. Máy bàn mà mình mua, mặc dù rẻ hơn laptop nhưng mạnh hơn nhiều, là con ASRock DeskMini X300, với CPU Ryzen 5 5600G (6 nhân 12 luồng). Máy chạy nhanh, mát, ít tốn điện nên mình cho nó bật 24/24 và làm công cụ kiếm cơm chính luôn. Dù đi đâu thì mình vẫn truy cập từ xa vào nó. Đặc biệt, công việc của mình cũng thường phải chạy biên dịch code Rust, build ảnh Docker, là những tác vụ ngốn CPU, nên việc tận dụng sức mạnh của máy bàn sẽ giúp tiết kiệm thời gian hơn, làm việc năng suất hơn.

...

Setup EdgeDB for single-server deployment

Today, many people talk about microservice. The new-born EdgeDB also doesn't stay outside that trend. But not every website is applicable for microservice. Due to low traffic, low budget, some websites still prefer single-server deployment, meaning that everything, application and databases, are hosted in the same server. But EdgeDB lacks a traightforward documentation for this setup. This post is to guide how to do.

Install EdgeDB package

Follow this guide to install EdgeDB package on your server, but hold on before "Enable a systemd unit​" section.

Setup simple authentication for EdgeDB

...

"Oxy hóa" nền tảng IoT nông nghiệp bằng Rust

Trong giới lập trình, "oxy hóa" là một cách nói vui ám chỉ việc viết lại (một phần hoặc toàn bộ) một phần mềm bằng ngôn ngữ Rust, đây là một lối chơi chữ, vì "Rust" còn có nghĩa là "rỉ sét", một hiện tượng do sự oxy hóa gây nên. Gần đây mình cũng mạnh dạn oxy hóa một phần nền tảng IoT nông nghiệp của AgriConnect.

Động lực khiến mình viết lại nền tảng IoT của AgriConnect bằng Rust là để giảm tải hệ thống, tăng cường khả năng chịu áp lực trong tương lai. Phần mềm mình đang nói đến ở đây có tên mã là "Hạt Thóc". Nghe tên khiêm tốn, nhỏ bé thôi nhưng nó vận hành theo kiểu SaaS (Software as a Service), tức một phần mềm sẽ vận hành cùng lúc nhiều trang trại khách hàng. Mỗi khách hàng sẽ có một không gian riêng khi thao tác, quản lý trang trại của mình, thậm chí có tên miền riêng, nhưng thực ra tất cả đều đang được phục vụ bởi một chương trình trên server. Phần mềm này vốn được viết bằng ngôn ngữ Python, framework Django, được chia ra nhiều thành phần, mỗi thành phần chạy dưới dạng một process, một service riêng. Trong hoàn cảnh đặc thù của "Hạt Thóc" thì thì mình không "oxy hoá" theo kiểu, viết lại một vài hàm nào đó bằng Rust, biên dịch dưới dạng thư viện, rồi dùng Python import thư viện đó, mà viết lại toàn bộ thành phần con luôn. "Hạt Thóc" có ba thành phần chính:

  • Collector: Giao tiếp để thu thập dữ liệu cảm biến, trạng thái bật tắt của các tải, và lưu vào database.
  • ControlView: Cung cấp giao diện web để người dùng vào xem dữ liệu, cấu hình trang trại, đặt lịch, hay bật tắt tải bằng tay.
  • ControlCenter: Chạy ngầm để phân tích lịch, dữ liệu cảm biến để ra lệnh bật, tắt tải, kiểm tra tình trạng bất thường và phát đi cảnh báo.
...

Filter out bot visits from Gunicorn log

Our web is often written in Python, and to run the web app on production, we often use Gunicorn. Its log is also a resource for incident investigation. But the log of bot visits is so noisy. How to exclude them?

When running Gunicorn, we often have a config file for Gunicorn. We often name it gunicorn_conf.py, with content like this:

proc_name = 'awesome-web'
workers = 6
...

Theo dõi bài mới qua feeds

Vừa rồi có bạn đề nghị mình thêm tính năng RSS Feeds vào website để bạn ấy dễ theo dõi khi nào có bài mới, nên mình tranh thủ làm trong dịp nghỉ lễ. Bây giờ thì tính năng đã sẵn sàng.

Tuy gọi là RSS Feeds nhưng mình cung cấp feeds ở định dạng Atom và JSONFeed, thay vì RSS.

Trên đầu trang bạn sẽ thấy icon của feeds, để lấy URL

...