Suýt nữa tôi xoá một dịch vụ đang chạy — chỉ vì đồng bộ một file cấu hình
Hôm nay tôi suýt xoá một dịch vụ đang chạy. Không phải vì viết sai code. Vì bấm một nút đồng bộ mà tôi tưởng là an toàn.
Việc của hôm nay nghe rất gọn: đưa cả hệ thống bot về một tên miền duy nhất — bot.ngochinguyen.com. Trước đó mỗi mảng nằm một nơi: chỗ quản trị một địa chỉ, cổng khách hàng một địa chỉ, đường nhận tin từ Facebook một địa chỉ khác. Tôi muốn gom hết về một nhà, mỗi mảng là một lối đi nhỏ trong cùng cái cổng: /admin, /portal, /webhook, /health.
Phần khó không nằm ở đó. Phần khó là một thứ tôi không hề chờ đợi.
Cái file đứng gác cổng
Để gom được về một tên miền, tôi phải sửa cái file điều khiển người gác cổng của hệ thống — phần mềm đứng trước, nhận mọi yêu cầu từ ngoài internet rồi quyết định đẩy nó vào lối đi nào bên trong. Khách gõ /portal, người gác cổng dẫn tới cổng khách hàng. Facebook gọi /webhook, nó dẫn tới chỗ nhận tin.
Toàn bộ luật dẫn đường đó nằm trong một file cấu hình. Và như mọi thứ trong dự án, tôi giữ một bản của file đó trong kho code của mình — chỗ được coi là bản gốc, là sự thật.
Quy trình quen thuộc của tôi: sửa file trong kho code ở máy, rồi đẩy nó lên server để server chạy đúng bản mới nhất. Code là gốc, server chỉ là cái bóng của code. Đó là cả triết lý của "hạ tầng viết bằng code": đừng bao giờ sửa tay trên máy chủ, hãy sửa ở bản gốc rồi đồng bộ xuống. Nghe rất kỷ luật.
Vấn đề là chữ "đồng bộ" đó giả định một điều: bản gốc và cái bóng vẫn giống nhau.
Lúc tôi nhận ra chúng đã không còn giống nhau
Trước khi đẩy file mới lên, tôi làm một việc mà bình thường tôi hay lười: tôi tải file đang chạy trên server về, đặt cạnh file trong kho code, rồi so từng dòng.
Chúng không khớp.
Trên server có một đoạn mà trong kho code của tôi không có — một lối đi tên /covan, dẫn tới một dịch vụ tư vấn mà ở lần làm trước tôi đã thêm thẳng trên máy chủ cho nhanh, rồi quên bẵng không chép ngược về bản gốc. Nó vẫn đang chạy. Vẫn đang phục vụ. Chỉ là kho code của tôi không hề biết nó tồn tại.
Đây là khoảnh khắc lạnh gáy. Nếu tôi làm theo phản xạ — "đẩy file mới đè lên file cũ" — thì file mới của tôi không có đoạn /covan. Sau khi đè, người gác cổng nạp lại luật mới, và lối đi /covan biến mất. Dịch vụ đó vẫn sống trong máy, nhưng từ ngoài internet không ai gọi vào được nữa. Một dịch vụ đang chạy bị một thao tác "dọn dẹp" lặng lẽ khoá cửa.
Không có dòng lỗi nào báo. Không có gì đỏ lên. Mọi bài kiểm tra vẫn xanh — vì tôi có viết bài kiểm tra nào cho cái lối đi mà chính kho code còn chưa biết đến đâu.
Trôi dạt — kẻ giết người thầm lặng của người làm một mình
Cái bẫy này có một tên: cấu hình trôi dạt. Bản gốc của bạn và cái máy thật từ từ khác nhau, từng chút một, mỗi lần bạn "sửa nhanh trên server cho kịp" rồi quên chép về.
Với một đội ngũ, có quy trình ngăn chuyện này: không ai được chạm tay vào server, mọi thay đổi phải đi qua bản gốc. Nhưng người làm một mình thì khác. Hai giờ sáng, khách cần một thứ gấp, bạn SSH thẳng vào máy chủ sửa một dòng cho xong việc. Nó chạy. Bạn nhẹ người. Bạn đóng máy đi ngủ.
Bạn vừa tạo ra một sự thật mà bản gốc không biết. Và lần sau bạn đồng bộ "đúng quy trình", chính cái quy trình đó sẽ xoá đi sự thật mà bạn quên ghi lại.
Nguy hiểm nhất không phải lúc bạn cẩu thả. Nguy hiểm nhất là lúc bạn làm đúng bài — đồng bộ từ bản gốc xuống — nhưng bản gốc đã sai từ lúc nào không hay.
Cách tôi tháo ngòi — và cách tôi sửa gốc
Việc trước mắt thì dễ xử khi đã thấy: tôi gộp có chủ đích, không đè mù. Lấy đoạn mới cho tên miền mới, ghép thêm vào đoạn /covan đang chạy, rồi mới đẩy lên. Sau khi đẩy, tôi kiểm thật từng lối đi: gõ /health phải báo "ổn", gõ vào gốc phải tự nhảy về cổng khách hàng, các đường cũ không được vỡ. Đủ xanh thật mới yên tâm.
Nhưng đó mới là vá cái triệu chứng. Cái gốc là: tại sao bản gốc của tôi lại tụt hậu so với máy thật?
Nên tôi làm thêm một bước mà tôi nghĩ mới là bài học thật: tôi chép ngược đoạn /covan từ server về kho code, lưu lại như một phần chính thức của bản gốc. Từ giờ trong code có đầy đủ những gì máy thật đang chạy. Bản gốc lại đúng nghĩa là sự thật.
Hạ tầng viết bằng code chỉ an toàn khi bản gốc và máy thật không trôi khỏi nhau. Khoảnh khắc chúng trôi, cái "kỷ luật đồng bộ" của bạn lật mặt thành con dao.
Bài học mang đi
Tôi rút ra ba điều, và cả ba đều không phải về phần mềm gác cổng — chúng đúng cho mọi thứ bạn vừa giữ bản gốc vừa chạy trên máy thật:
Một, đừng bao giờ đồng bộ bằng cách đè mù. Trước khi đẩy đè bất cứ thứ gì, hãy tải bản đang chạy về và so từng dòng với bản của bạn. Mười giây so sánh đó hôm nay đã cứu tôi khỏi một sự cố thật.
Hai, mỗi lần sửa tay trên server là một món nợ. Nó không tệ — đôi khi phải làm để kịp việc. Nhưng nợ thì phải ghi sổ. Sửa xong trên máy chủ, chép ngược về bản gốc ngay, trước khi bạn quên.
Ba, "đang chạy" không có nghĩa là "đã được ghi lại". Thứ nguy hiểm nhất với người ship một mình không phải cái hỏng ồn ào — đó là thứ đang âm thầm chạy mà bản gốc của bạn không hề biết tới. Một ngày nào đó một thao tác "dọn dẹp" sẽ vô tình tắt nó, và bạn sẽ mất nửa đêm đi tìm xem mình đã xoá mất cái gì.
Người làm một mình không có ai gác cổng giùm cái kỷ luật này. Bạn vừa là người sửa tay lúc hai giờ sáng, vừa là người phải dọn hậu quả ba tuần sau. Cách duy nhất sống sót là bắt chính mình kiểm tra trước khi bấm — nhất là khi thao tác trông an toàn nhất.
👉 Muốn tự tay build con bot AI đầu tiên tới chỗ hiểu cảm giác "đổi nền móng dưới một dịch vụ đang chạy" này? Bắt đầu với mini-course miễn phí: Bot AI đầu tiên của bạn — làm xong trong một buổi tối, và bạn sẽ có một sản phẩm thật để bắt đầu nghĩ như một người vận hành, không chỉ một người viết code.