Micro-frontend Learning
Xử lý sự cố

Xử lý sự cố

Khoanh vùng lỗi micro-frontend bằng release thực chạy, request thất bại và integration boundary; chọn đúng runbook và phục hồi an toàn.

Shell vẫn hiện header nhưng catalog trắng trang. Hoặc tab mới chạy bình thường, còn tab mở từ trước deploy báo ChunkLoadError. Cùng một màn hình hỏng có thể bắt nguồn từ config, tải assets, shared runtime, routing, CSS hoặc API. Nếu bắt đầu bằng xóa cache hay đổi singleton, bạn có thể làm mất dấu lỗi mà chưa sửa được nguyên nhân.

Trang này là điểm bắt đầu để tìm boundary đầu tiên bị lỗi, giữ bằng chứng và chọn đúng bài xử lý chi tiết. Mình ưu tiên Network, Console và release thực chạy trước khi thay đổi cấu hình; khi người dùng đang bị ảnh hưởng, giảm tác động song song với điều tra.

Phạm vi và ví dụ

Các ví dụ dùng shop giả định gồm shell, catalog và cart. Phần remote entry/shared dependencies chủ yếu áp dụng cho Webpack 5 Module Federation chạy trong browser; với Vite/ESM, runtime enhanced, iframe hoặc SSR, cần kiểm tra cơ chế của đúng loader/framework.

Release IDs, URL và incident record dưới đây chỉ là minh họa. Repo này chứa site tài liệu, không có hệ thống shop hay CDN production để chạy thao tác phục hồi.

Mục lục

Nếu người dùng đang bị ảnh hưởng

Đừng chờ biết mọi chi tiết mới bảo vệ journey đang lỗi. Nhưng cũng đừng retry hay reload hàng loạt khi chưa biết một thao tác ghi đã thành công hay chưa.

  1. Xác định ảnh hưởng. Journey nào hỏng, người dùng nào bị ảnh hưởng, còn đường nào dùng được? Phân biệt một remote optional mất với checkout không thể hoàn tất.
  2. Dừng mở rộng thay đổi liên quan. Pause rollout của candidate nghi vấn và ghi selection revision hiện tại. Deploy gần thời điểm lỗi là đầu mối, chưa phải kết luận nguyên nhân.
  3. Giữ shell và fallback hoạt động. Cô lập vùng lỗi theo failure policy; thông báo rõ phần không khả dụng. Không hiển thị “giỏ hàng trống” nếu thực ra chưa tải được giỏ hàng.
  4. Bảo toàn kết quả nghiệp vụ. Với request đặt hàng/thanh toán chưa rõ outcome, kiểm tra trạng thái qua API theo contract trước khi retry. Lỗi UI không chứng minh backend chưa xử lý.
  5. Dùng đường phục hồi đã kiểm chứng. Rollback đúng remote/config hoặc khôi phục artifact bị thiếu khi có bằng chứng; xác nhận target còn tương thích và còn tải được.

Rollback selection không thay code đã chạy

Document có thể giữ config snapshot, module đã evaluate và shared instance đã consume. Đổi pointer về release cũ không đảm bảo tab đang mở tự chuyển sang release đó. Cần kế hoạch riêng cho document mới và tab cũ; không hot-swap hay ép reload khi còn state chưa lưu hoặc pending writes.

Nếu thấy nguồn code lạ, artifact bị sửa ngoài quy trình hoặc publish credentials bị lộ, chuyển sang security incident response. Rollback UI chưa đủ để xác nhận session, dữ liệu và chuỗi publish vẫn an toàn. Xem Security và trust boundaries và Resilience khi remote lỗi.

Chọn runbook theo triệu chứng

Bảng này chỉ ra nơi bắt đầu, không ánh xạ chắc chắn một error string sang một nguyên nhân. Giữ nguyên lỗi đầu tiên và request tương ứng; thông báo của runtime có thể khác theo plugin/version.

Triệu chứng bạn thấyBằng chứng nên kiểm tra trướcRunbook
Remote không xuất hiện, entry không tải được, ScriptExternalLoadErrorRoute đã gọi import chưa; URL thực tế, status/body, policy browser, container name và formatRemote không tải được
Entry 200 nhưng báo Unexpected token '<' hoặc MIME errorResponse có phải HTML từ SPA fallback/login/proxy khôngRemote không tải được
Invalid hook call, standalone chạy nhưng tích hợp lỗiRules of Hooks, React–renderer compatibility và module identityDuplicate React và Invalid Hook Call
Unsatisfied version, shared singleton mismatch hoặc lỗi eager consumptionConsumer range, provider version, share scope, bootstrap và thứ tự loadShared version mismatch
Refresh deep link 404, Back/Forward lệch màn hìnhDocument response, base path, route contract và writer của browser historyLỗi routing và CSS
Style lan sang remote khác, modal sai style, font/ảnh mấtCSS request, asset base, computed styles, selector và portal targetLỗi routing và CSS
ChunkLoadError, lỗi sau deploy hoặc chỉ tab cũ lỗiChunk URL/status/body, release graph, nguồn response và artifact retentionCache lỗi thời và chunk errors
UI đã render nhưng API lỗi hoặc state nghiệp vụ saiAPI request/outcome, auth, payload contract và event flowGiao tiếp và trạng thái cùng runbook backend tương ứng
Không biết browser đang dùng tổ hợp release nàoSelected/loaded/ready signals, config revision và correlation IDObservability

Một chunk tải nhầm origin thường cần kiểm tra publicPath/asset base; chunk đúng URL nhưng bị xóa sau deploy cần kiểm tra retention. Đừng mặc định mọi ChunkLoadError đều do cache.

Tìm boundary đầu tiên bị lỗi

Dùng đường đi này làm bản đồ điều tra:

direction: right
n0: "Selection / config"
n1: "Entry + chunks"
n2: "Runtime / contract"
n3: "UI tích hợp"
n4: "Domain action"
n0 -> n1 -> n2 -> n3 -> n4
Selection / configEntry + chunksRuntime / contractUI tích hợpDomain action
Selection / configEntry + chunksRuntime / contractUI tích hợpDomain action
Tìm boundary đầu tiên bị lỗi

Đây là các nhóm kiểm tra, không phải thứ tự nội bộ tuyệt đối. Trong federation, initialize sharing, lấy module và tải shared chunks có thể xen kẽ. Runtime dùng manifest có thêm request manifest; iframe có document riêng; SSR còn có bước tải/evaluate phía server.

BoundaryCâu hỏi cần trả lờiOwner thường cần phối hợp
Selection/configDocument chọn alias, URL và release nào? Config có hợp lệ và được consume không?Shell/loader và config publisher
Entry và chunksBrowser nhận đúng artifact không? Request đầu tiên fail do network, policy hay file thiếu?Remote publisher, CDN/platform và shell loader
Runtime/contractContainer/module key/export có đúng không? Shared dependency nào thực sự được dùng?Consumer/provider owners và platform runtime
UI tích hợpRender/mount, router, CSS và cleanup có đúng khi ghép vào shell không?Shell và remote owner
Domain actionAPI/event có đúng contract, quyền và outcome không?Domain frontend cùng backend/API owner

Tìm nơi hợp đồng bị phá vỡ trước khi giao ticket. Catalog sở hữu source không có nghĩa catalog team có quyền sửa CDN headers; shell nhận exception không có nghĩa shell là nguồn gây lỗi.

Quy trình khoanh vùng

Bước 1 Ghi phạm vi và release thực chạy

Ghi route, thời điểm kèm timezone, đường tái hiện, môi trường và hành vi mong đợi. So sánh tab cũ với document mới, navigation nội bộ với deep link/refresh, standalone với tích hợp qua shell. Những phép so sánh này giúp tách lỗi deploy, integration và state trong runtime.

Với mỗi remote, tách ba mốc:

  • Selected: config chọn release nào.
  • Loaded: loader đã tải/evaluate module thành công theo định nghĩa telemetry của hệ thống.
  • Ready: UI đã sẵn sàng theo contract, chẳng hạn catalog render được vùng sản phẩm.

Config chọn catalog r19 nhưng tải entry thất bại thì chỉ biết r19 được chọn, chưa biết r19 đã chạy. Nếu không có tín hiệu loaded/ready, ghi “chưa xác định” thay vì suy đoán từ tên branch hoặc source mới nhất.

Bước 2 Giữ bằng chứng ban đầu

Chụp hoặc lưu lỗi Console đầu tiên, stack/component stack và request liên quan trước khi reload. Bật Preserve log ở Network và Console cho lần tái hiện tiếp theo.

Với request entry, manifest, chunk hoặc CSS nghi vấn, giữ:

  • Request URL, method, status hoặc lý do blocked.
  • Response headers và phần body đủ để phân biệt artifact với HTML/error page.
  • Initiator, redirect chain và nguồn response: network, memory/disk cache hay service worker.
  • Release/config revision và correlation ID liên quan nếu đã có instrumentation.

Chỉ chia sẻ bằng chứng đã loại dữ liệu nhạy cảm

HAR, Copy as cURL, URL và response body có thể chứa cookie, Authorization, signed query, thông tin tài khoản hoặc dữ liệu nghiệp vụ. Loại bỏ chúng trước khi gửi qua kênh được phép; không đưa HAR nguyên bản vào ticket công khai. Không xóa toàn bộ storage người dùng chỉ để debug.

Bước 3 Tìm điểm thất bại đầu tiên

Bắt đầu từ lỗi sớm nhất trong cùng lần tái hiện, không phải exception cuối cùng của fallback.

  1. Chưa có request remote: kiểm tra route/lazy import đã chạy, config đã resolve và policy browser có chặn trước khi gửi không. Remote lazy chưa được mở có thể chưa cần tải.
  2. Có request nhưng thất bại: đọc URL, status, headers và body. Phân biệt DNS/TLS, quyền truy cập, CORS/CSP, redirect và asset thiếu.
  3. Assets nhận được nhưng module không dùng được: kiểm tra execute, container format/name, public module key, export contract và sharing initialization.
  4. Module dùng được nhưng UI sai: kiểm tra render/mount, provider hierarchy, router, CSS và lifecycle cleanup.
  5. UI ready nhưng thao tác sai: kiểm tra API/event và outcome nghiệp vụ; không tiếp tục đổi remote URL nếu đường tải code đã được xác nhận tốt.

Với SSR, dùng server logs/traces để kiểm tra phần request không xuất hiện trong DevTools. Một lỗi hydration cũng cần đối chiếu HTML server với render client; runbook client-side không bao phủ toàn bộ trường hợp này. Xem Next.js, SSR và giới hạn.

Bước 4 Kiểm chứng một giả thuyết mỗi lần

Viết giả thuyết kèm dấu hiệu có thể bác bỏ nó. Ví dụ: “chunk đang tải từ origin shell thay vì catalog” phải được kiểm chứng bằng Request URL và config asset base của artifact, không chỉ bằng việc thêm publicPath: 'auto' rồi thấy hết lỗi.

Giữ nguyên release set, route và thứ tự thao tác khi đối chiếu; thay một yếu tố mỗi lần trong môi trường được phép. Không đồng thời upgrade React, đổi remote URL và purge cache vì bạn sẽ không biết điều gì đã tạo ra khác biệt.

Sau khi giữ bằng chứng, có thể thử Disable cache khi DevTools mở và một document mới. Đây là phép đối chiếu HTTP cache của browser, không tự purge CDN, loại bỏ module đã evaluate hay bypass mọi service worker. Nếu có service worker, kiểm tra riêng cơ chế intercept/cache của nó.

Chọn runbook ở bảng trên khi đã biết boundary; các bài chi tiết có lệnh và cấu hình cho từng trường hợp. Nếu vẫn chưa rõ, quay lại request đầu tiên và release inventory thay vì thử thêm config ngẫu nhiên.

Những bằng chứng dễ bị hiểu nhầm

Điều đã quan sátĐiều nó thực sự chứng minhĐiều chưa được chứng minh
remoteEntry.js trả 200Request nhận được một response thành công ở lớp HTTPBody đúng JavaScript, script execute được, shared init và mọi chunk đều tốt
Standalone remote chạy đượcĐường bootstrap riêng của remote hoạt động trong môi trường đóFederated import, contract, provider/router và CSS khi ghép vào shell tương thích
Shell và remote khai báo cùng React versionMetadata/version giống nhau tại nơi được kiểm traComponent và renderer dùng cùng module instance
Đã bật singletonCó policy chọn shared singleton theo runtime/pluginRules of Hooks đúng hoặc mọi consumer đều tương thích với version được chọn
Hard reload hết lỗiDocument/runtime mới không tái hiện trong lần thử đóRoot cause đã được sửa hoặc tab cũ vẫn tải được chunks
curl nhận đúng JavaScriptHTTP endpoint dùng được từ môi trường chạy lệnhBrowser vượt CORS/CSP, service worker không can thiệp và JavaScript chạy được
Không còn exception sau rollbackKênh quan sát chưa thấy exception tương ứngRemote đã ready, journey đã thành công hay tab cũ đã rời candidate lỗi

Đừng tắt version checks, thêm eager: true hàng loạt, mở CORS cho mọi origin hoặc chèn !important chỉ để thông báo biến mất. Những thay đổi đó có thể che lỗi hoặc mở rộng rủi ro; chỉ áp dụng khi đã xác định nguyên nhân và kiểm thử đúng boundary.

Ví dụ tab cũ lỗi sau deploy

Giả sử shell s17 chọn catalog r18 trong tab A. Sau khi publish r19, document mới B dùng r19 và hoạt động bình thường. Tab A mở trang sản phẩm lazy thì báo ChunkLoadError.

Nếu chỉ nhìn selection hiện tại là r19, bạn dễ điều tra nhầm artifact. Trình tự hữu ích hơn là:

  1. Giữ lỗi, Request URL và nguồn response của A. Xác nhận A đang giữ entry/runtime r18, chưa chuyển sang r19.
  2. Thấy request tới /catalog/releases/r18/product.a1b2.js trả 404; đây là URL đúng release cũ, không phải request bị trỏ nhầm về shell.
  3. Đối chiếu inventory ở origin và log pipeline: giả sử có bằng chứng job cleanup đã xóa chunk r18 trong khi entry/runtime còn tham chiếu nó.
  4. Khôi phục artifact r18 chính xác từ nguồn build tin cậy theo quy trình. Không đặt bytes của r19 vào URL r18 vì sẽ phá tính bất biến và graph của release cũ.
  5. Kiểm tra origin/CDN trả đúng file; nếu CDN còn cache response 404, xử lý đúng object theo policy. Xác minh lần tải lại trên client theo cơ chế retry được loader hỗ trợ; không mặc định import lỗi sẽ tự retry thành công.
  6. Sửa retention và deploy gate để giữ graph cho tab cũ cùng target rollback, rồi kiểm thử lại chu trình deploy.

Đổi pointer về r18 một mình không phục hồi file đã bị xóa. Purge cache cũng không tạo lại artifact thiếu ở origin. Ca này đi tiếp ở Cache lỗi thời và chunk errors, không cần sửa React sharing.

Phục hồi và xác nhận đã sửa

Chọn hành động theo bằng chứng, không theo mức độ quen thuộc của thao tác:

Nguyên nhân đã xác nhậnHướng phục hồiĐiều cần tránh
Config chọn sai URL/releasePublish revision hợp lệ, tương thích và xác nhận loader consume nóSửa source config nhưng quên document/bundle vẫn giữ giá trị cũ
Artifact bị thiếuKhôi phục đúng artifact, sửa publish/retention và cache response lỗi khi cầnOverwrite URL bất biến bằng bytes của release khác
Shared runtime hoặc public contract không tương thíchChọn release set đã kiểm chứng; sửa policy/contract và rebuild qua pipelineTắt strictVersion để hợp thức hóa tổ hợp chưa được test
Routing hoặc CSS regressionRollback bản gây lỗi hoặc sửa đúng route/style boundaryRedirect mọi URL về trang chủ, dùng CSS override toàn cục để che lỗi
API/write outcome chưa rõĐối chiếu trạng thái backend; retry theo idempotency contractCoi timeout hoặc UI trắng là thao tác chưa được thực hiện

Sau phục hồi, tối thiểu kiểm tra:

  • Document mới chọn, load và ready đúng release set dự kiến.
  • Tab cũ vẫn tải được lazy assets hoặc có recovery flow an toàn đã kiểm chứng.
  • Journey lỗi ban đầu hoạt động, gồm kết quả API/state chứ không chỉ render giao diện.
  • Deep link, refresh, navigation và Back/Forward đúng nếu boundary đó bị tác động.
  • Mount/unmount/remount không để lại listeners, history writers hoặc styles gây lỗi.
  • Không có retry/reload loop; fallback không báo sai state và shell vẫn dùng được.
  • Telemetry xác nhận journey success và mức degraded giảm, không chỉ exception giảm.
  • Có regression test gắn với nguyên nhân cùng owner cho phần sửa lâu dài.

Chạy qua shell với artifacts/release set thực cần hỗ trợ. Chỉ test HEAD của mọi app có thể bỏ sót tổ hợp mà người dùng đang chạy; xem Integration và E2E và Rollout và rollback.

Thông tin bàn giao cho owner

Một ticket hữu ích cần đủ để owner tái hiện và phân biệt điều đã biết với giả thuyết. Dùng mẫu dưới đây, bỏ các trường không có và ghi rõ “chưa xác định” ở dữ kiện quan trọng còn thiếu.

Mẫu incident record đã loại dữ liệu nhạy cảm
Journey/route: mở sản phẩm từ catalog
Môi trường/thời điểm: production, <timestamp kèm timezone>
Phạm vi: tab cũ lỗi; document mới chưa tái hiện
Shell release / config revision: s17 / cfg42
Remote selected / loaded / ready: ghi riêng cho từng remote
Loader/plugin và version: <giá trị từ build/runtime metadata>
Đường tái hiện: <route ban đầu → thao tác → lỗi>
Mong đợi / thực tế: <hành vi cần có> / <hành vi quan sát>
Lỗi đầu tiên và phase: <error + load/evaluate/mount/action>
Request liên quan: <URL đã làm sạch, status, initiator, nguồn response>
Correlation ID: <nếu có và được phép chia sẻ>
Bằng chứng: <stack, headers/body tối thiểu, release inventory>
Giả thuyết / phép kiểm chứng: <tách khỏi kết luận đã xác nhận>
Giảm tác động: <hành động, thời điểm, kết quả>
Owner cần phối hợp: <shell, remote, CDN, runtime hoặc backend>
Phục hồi đã kiểm tra: <document mới, tab cũ, journey outcome>
Việc còn lại: <regression test, policy, owner và tiêu chí hoàn tất>

Nếu release chưa load được, không điền selected release vào cột loaded. Nếu không có Console error nhưng UI sai, vẫn ghi hành vi và network/event evidence; troubleshooting không chỉ dành cho exception.

Tài liệu tham khảo

Các bài trong nhóm

On this page