14 thg 3, 2025·8 phút đọc

Tác vụ nền với cập nhật tiến trình: mẫu UI hiệu quả

Tìm hiểu các mẫu thực tiễn cho tác vụ nền có cập nhật tiến trình: hàng đợi, mô hình trạng thái, thông điệp UI, hành động hủy và thử lại, và báo cáo lỗi.

Tác vụ nền với cập nhật tiến trình: mẫu UI hiệu quả

Tại sao người dùng mắc kẹt khi tác vụ chạy nền

Các hành động mất nhiều thời gian không nên chặn UI. Người dùng chuyển tab, mất kết nối, đóng laptop, hoặc chỉ tự hỏi có gì đang xảy ra. Khi màn hình bị đóng băng, người dùng phỏng đoán, và phỏng đoán dẫn đến nhấp nhiều lần, gửi trùng lặp, và phiền toái cho support.

Công việc nền tốt thực chất là về sự tin tưởng. Người dùng cần ba thứ:

  • Một trạng thái rõ ràng (queued, running, done)
  • Một ước lượng thời gian (dù là thô)
  • Một hành động tiếp theo rõ ràng (chờ, tiếp tục làm việc, hủy, hoặc quay lại sau)

Không có những thứ đó, công việc có thể đang chạy bình thường, nhưng trải nghiệm lại cảm thấy hỏng.

Một nhầm lẫn phổ biến là coi một request chậm là công việc nền thực sự. Một request chậm vẫn là một cuộc gọi web khiến người dùng chờ. Công việc nền khác: bạn khởi tạo job, nhận xác nhận ngay, và phần xử lý nặng diễn ra ở nơi khác trong khi UI vẫn dùng được.

Ví dụ: người dùng tải lên một CSV để import khách hàng. Nếu UI bị chặn, họ có thể refresh, upload lại và tạo bản ghi trùng. Nếu import chạy nền và UI hiển thị một thẻ công việc với tiến trình và nút Cancel an toàn, họ có thể tiếp tục làm việc và quay lại với kết quả rõ ràng.

Các thành phần cơ bản: job, queue, worker và trạng thái

Khi nói về tác vụ nền với cập nhật tiến trình, thường có bốn phần hoạt động cùng nhau.

Một job là đơn vị công việc: "import file CSV này", "tạo báo cáo này", hoặc "gửi 5.000 email." Một queue là hàng đợi nơi job chờ đến lượt. Một worker lấy job từ queue và thực hiện công việc (lần lượt hoặc song song).

Với UI, phần quan trọng nhất là trạng thái vòng đời của job. Giữ số trạng thái ít và dễ dự đoán:

  • Queued: đã nhận, chờ worker
  • Running: đang xử lý
  • Done: hoàn tất thành công
  • Failed: dừng do lỗi

Mỗi job cần một job ID (tham chiếu duy nhất). Khi người dùng nhấn nút, trả ID đó ngay lập tức và hiển thị một dòng “Task started” trong bảng tác vụ.

Rồi bạn cần một cách hỏi: "Bây giờ chuyện gì đang xảy ra?" Thường là một endpoint trạng thái (hoặc bất kỳ phương thức đọc nào) nhận job ID và trả về trạng thái cộng thông tin tiến trình. UI dùng nó để hiển thị phần trăm hoàn thành, bước hiện tại và bất kỳ thông điệp nào.

Cuối cùng, trạng thái phải sống trong kho lưu bền, không chỉ trong bộ nhớ. Worker có thể crash, app khởi động lại, người dùng refresh trang. Lưu trữ bền là thứ khiến tiến trình và kết quả đáng tin cậy. Ít nhất, lưu:

  • trạng thái hiện tại và timestamps
  • giá trị tiến trình (phần trăm hoặc số lượng)
  • tóm tắt kết quả (đã tạo hoặc thay đổi gì)
  • chi tiết lỗi (cho debug và thông điệp thân thiện với người dùng)

Nếu bạn xây dựng trên nền tảng như AppMaster, hãy xem kho trạng thái như bất kỳ data model nào khác: UI đọc theo job ID, worker cập nhật khi di chuyển qua các bước.

Chọn mẫu queue phù hợp khối lượng công việc

Mẫu queue bạn chọn thay đổi cảm nhận “công bằng” và dự đoán của ứng dụng. Nếu một tác vụ bị kẹt sau nhiều công việc khác, người dùng cảm thấy độ trễ ngẫu nhiên, dù hệ thống vẫn khỏe mạnh. Vì vậy lựa chọn queue là quyết định UX, không chỉ hạ tầng.

Queue đơn giản dựa trên database thường đủ khi lượng thấp, job ngắn và bạn chịu được vài lần retry. Nó dễ triển khai, dễ kiểm tra, và bạn có thể giữ mọi thứ ở một nơi. Ví dụ: admin chạy báo cáo hàng đêm cho nhóm nhỏ. Nếu retry một lần, không ai hoảng.

Khi throughput tăng, job nặng hoặc yêu cầu độ tin cậy cao, bạn thường cần hệ thống queue chuyên dụng. Import, xử lý video, thông báo hàng loạt và bất kỳ workflow nào cần chạy qua restart đều hưởng lợi từ cô lập, tầm nhìn và retry an toàn hơn. Điều này ảnh hưởng tới tiến trình hiển thị cho người dùng vì họ dễ nhận thấy cập nhật bị thiếu và trạng thái kẹt.

Cấu trúc queue còn ảnh hưởng ưu tiên. Một queue duy nhất đơn giản, nhưng trộn công việc nhanh và chậm có thể làm hành động nhanh cảm thấy chậm. Tách queue giúp khi bạn có công việc do người dùng kích hoạt cần cảm giác tức thì cùng lúc với công việc batch có thể chờ.

Thiết lập giới hạn concurrency có chủ ý. Quá song song có thể quá tải database và khiến tiến trình nhảy lung tung. Quá ít thì hệ thống chậm. Bắt đầu với concurrency nhỏ, ổn định cho mỗi queue, rồi tăng khi bạn giữ được thời gian hoàn thành ổn định.

Thiết kế mô hình tiến trình để thực sự hiển thị được trong UI

Nếu mô hình tiến trình mơ hồ, UI sẽ mơ hồ. Quyết định hệ thống có thể báo gì trung thực, tần suất thay đổi và người dùng nên làm gì với thông tin đó.

Một schema trạng thái đơn giản mà hầu hết job có thể hỗ trợ như sau:

  • state: queued, running, succeeded, failed, canceled
  • percent: 0-100 khi bạn đo được
  • message: một câu ngắn người dùng hiểu được
  • timestamps: created, started, last_updated, finished
  • result_summary: số lượng như processed, skipped, errors

Tiếp theo, định nghĩa “tiến trình” nghĩa là gì.

Phần trăm hợp lý khi có mẫu số thực (số dòng trong file, email cần gửi). Nó gây hiểu nhầm khi công việc không dự đoán được (chờ bên thứ ba, compute thay đổi, query nặng). Trong những trường hợp đó, tiến trình theo bước đáng tin hơn vì nó tiến lên theo các khối rõ ràng.

Một quy tắc thực tế:

  • Dùng percent khi bạn có thể báo “X của Y”.
  • Dùng steps khi thời lượng không biết trước (Validate file, Import, Rebuild indexes, Finalize).
  • Dùng indeterminate khi cả hai đều không đúng, nhưng giữ thông điệp mới mẻ.

Lưu kết quả từng phần khi job chạy. Điều đó cho phép UI hiển thị thứ hữu ích trước khi job kết thúc, như số lỗi đang tăng hoặc bản xem trước thay đổi. Với import CSV, bạn có thể lưu rows_read, rows_created, rows_updated, rows_rejected, cùng vài thông báo lỗi gần nhất.

Đây là nền tảng cho tác vụ nền có cập nhật tiến trình mà người dùng tin tưởng: UI bình tĩnh, con số tiến dần, và tóm tắt “chuyện gì đã xảy ra?” sẵn sàng khi job kết thúc.

Cách truyền cập nhật tiến trình: polling, push và hybrid

Kết nối messaging khi hoàn tất
Gửi cảnh báo Telegram hoặc email khi công việc hoàn tất để người dùng tiếp tục làm việc.
Thêm cảnh báo

Đưa tiến trình từ backend lên màn hình là nơi nhiều triển khai thất bại. Chọn phương thức phù hợp với tần suất thay đổi và số lượng người xem.

Polling là đơn giản nhất: UI hỏi trạng thái mỗi N giây. Mặc định tốt là 2–5 giây khi người dùng đang nhìn, rồi giảm dần theo thời gian. Nếu tác vụ chạy lâu hơn một phút, chuyển sang 10–30 giây. Nếu tab ở background, giảm hơn nữa.

Push (WebSockets, server-sent events, hoặc thông báo mobile) hữu ích khi tiến trình thay đổi nhanh hoặc người dùng quan tâm “ngay lúc này.” Push tốt cho tính kịp thời, nhưng bạn vẫn cần fallback khi kết nối rớt.

Cách tiếp cận hybrid thường là tốt nhất: polling nhanh lúc đầu (để UI nhanh thấy queued thành running), rồi chậm lại khi job ổn định. Nếu bạn thêm push, giữ polling chậm như mạng lưới an toàn.

Khi cập nhật dừng, coi đó như một trạng thái quan trọng. Hiển thị “Last updated 2 minutes ago” và đề nghị làm mới. Ở backend, đánh dấu job là stale nếu không có heartbeat.

Mẫu UI cho tác vụ chạy dài mà rõ ràng

Sự rõ ràng đến từ hai thứ: một tập trạng thái nhỏ, dự đoán được, và nội dung (copy) nói cho người dùng biết chuyện gì sẽ xảy ra tiếp theo.

Gọi tên trạng thái trong UI, không chỉ ở backend. Một job có thể queued (chờ tới lượt), running (đang làm), waiting for input (cần lựa chọn), completed, completed with errors, hoặc failed. Nếu người dùng không phân biệt được, họ sẽ cho là app bị kẹt.

Dùng copy rõ ràng, hữu ích bên cạnh chỉ báo tiến trình. “Importing 3,200 rows (1,140 processed)” tốt hơn “Processing.” Thêm một câu trả lời: tôi có thể rời đi không và điều gì sẽ xảy ra? Ví dụ: “Bạn có thể đóng cửa sổ này. Chúng tôi sẽ tiếp tục import ở nền và thông báo khi xong.”

Nơi hiển thị tiến trình nên phù hợp ngữ cảnh người dùng:

  • Modal phù hợp khi tác vụ chặn bước tiếp theo (ví dụ tạo PDF hóa đơn họ cần ngay).
  • Toast phù hợp cho tác vụ nhanh, không cần gián đoạn.
  • Tiến trình inline trong hàng bảng phù hợp cho thao tác theo mục.

Với bất cứ thứ gì dài hơn một phút, thêm trang Jobs (hoặc panel Activity) để người dùng tìm công việc sau.

Giao diện tác vụ dài rõ ràng thường bao gồm nhãn trạng thái với thời gian cập nhật cuối, thanh tiến trình (hoặc bước) với một dòng chi tiết, hành vi Cancel an toàn, và khu vực kết quả với tóm tắt và hành động tiếp theo. Giữ các job hoàn tất dễ tìm để người dùng không bị buộc phải đợi trên một màn hình.

Báo “hoàn tất với lỗi” mà không làm người dùng hoang mang

Thêm trang Jobs nhanh
Tạo một chế độ Activity để người dùng rời đi rồi quay lại với kết quả rõ ràng.
Xây dựng trong AppMaster

“Hoàn tất” không phải lúc nào cũng là chiến thắng. Khi một công việc xử lý 9.500 bản ghi và 120 lỗi, người dùng cần hiểu chuyện gì đã xảy ra mà không phải đọc logs.

Đối xử với thành công một phần như một kết quả bình thường. Ở dòng trạng thái chính, hiển thị cả hai: “Imported 9,380 of 9,500. 120 failed.” Điều này giữ niềm tin cao vì hệ thống trung thực, và xác nhận rằng dữ liệu đã được lưu.

Rồi hiển thị một tóm tắt lỗi nhỏ người dùng có thể hành động: “Missing required field (63)” và “Invalid date format (41).” Ở trạng thái cuối, “Completed with issues” thường rõ ràng hơn “Failed,” vì nó không ngụ ý rằng không có gì hoạt động.

Báo cáo lỗi có thể xuất ra biến sự bối rối thành danh sách việc cần làm. Giữ nó đơn giản: số dòng hoặc định danh mục, danh mục lỗi, thông điệp thân thiện, và tên trường khi liên quan.

Đặt hành động tiếp theo rõ ràng gần tóm tắt: sửa dữ liệu và thử lại các mục lỗi, tải báo cáo lỗi, hoặc liên hệ support nếu có vẻ là sự cố hệ thống.

Hủy và thử lại người dùng có thể tin tưởng

Cancel và Retry trông đơn giản nhưng phá niềm tin nhanh khi UI nói một đằng còn hệ thống làm một nẻo. Xác định ý nghĩa của Cancel cho từng loại job, rồi phản ánh trung thực trong giao diện.

Thường có hai chế độ hủy hợp lệ:

  • “Stop now”: worker kiểm tra cờ hủy thường xuyên và thoát nhanh.
  • “Stop after this step”: bước hiện tại hoàn tất, rồi job dừng trước bước tiếp theo.

Trong UI, hiển thị trạng thái trung gian như “Cancel requested” để người dùng không nhấp liên tục.

Làm cho hủy an toàn bằng cách thiết kế công việc có thể lặp lại. Nếu job ghi dữ liệu, ưu tiên thao tác idempotent (an toàn chạy lại) và làm cleanup khi cần. Ví dụ, nếu import CSV tạo bản ghi, lưu job-run ID để bạn có thể xem những gì đã thay đổi trong lần chạy #123.

Retry cần cùng mức độ rõ ràng. Thử lại cùng instance job hợp lý khi có thể resume. Tạo job mới an toàn hơn khi bạn muốn một lần chạy sạch với timestamp và audit trail mới. Dù chọn cách nào, giải thích rõ điều gì sẽ xảy ra và điều gì sẽ không.

Các guardrail giữ hủy và retry dự đoán được:

  • Giới hạn số lần retry và hiển thị số lần đã thử.
  • Ngăn retry khi job đang chạy.
  • Yêu cầu xác nhận khi retry có thể tạo ra side effect trùng (email, thanh toán, export).
  • Hiển thị lỗi cuối và bước thành công cuối cùng trong panel chi tiết.

Từng bước: luồng end-to-end từ nhấp tới hoàn tất

Phát hành giao diện import CSV
Kết hợp xử lý backend và giao diện thẻ tiến trình trong cùng một dự án AppMaster.
Bắt đầu dự án

Luồng end-to-end tốt bắt đầu với một quy tắc: UI không bao giờ chờ công việc thực tế. Nó chỉ chờ job ID.

Luồng (từ nhấp của người dùng đến trạng thái cuối)

  1. Người dùng khởi động tác vụ, API trả nhanh. Khi người dùng nhấn Import hoặc Generate report, server tạo record job và trả về job ID duy nhất ngay.

  2. Enqueue công việc và đặt trạng thái ban đầu. Đưa job ID vào queue và đặt trạng thái thành queued với progress 0%. Điều này cho UI thứ thực tế để hiển thị ngay cả trước khi worker nhận việc.

  3. Worker chạy và báo tiến trình. Khi worker bắt đầu, đặt trạng thái thành running, lưu thời gian bắt đầu, và cập nhật tiến trình từng bước nhỏ, trung thực. Nếu không đo được phần trăm, hiển thị các bước như Parsing, Validating, Saving.

  4. UI giữ người dùng định hướng. UI poll hoặc subscribe cập nhật và render các trạng thái rõ ràng. Hiển thị thông điệp ngắn (đang làm gì) và chỉ các hành động phù hợp trong thời điểm đó.

  5. Hoàn tất với kết quả bền vững. Khi kết thúc, lưu thời gian kết thúc, output (tham chiếu download, ID đã tạo, tóm tắt số lượng), và chi tiết lỗi. Hỗ trợ finished-with-errors như một kết quả riêng, không phải success mơ hồ.

Quy tắc Cancel và Retry

Cancel nên rõ ràng: Yêu cầu hủy job, worker xác nhận và đánh dấu canceled. Retry nên tạo job ID mới, giữ bản gốc làm lịch sử, và giải thích sẽ chạy lại những gì.

Ví dụ: import CSV với tiến trình và lỗi từng phần

Biến polling thành một mẫu
Đặt một endpoint trạng thái đơn giản và nhịp làm mới UI giữ phản hồi.
Xây dựng ngay

Một chỗ phổ biến cần cập nhật tiến trình là import CSV. Hình dung CRM nơi sales ops tải lên customers.csv với 8.420 dòng.

Ngay sau upload, UI nên chuyển từ “Tôi nhấn nút” sang “một job tồn tại, bạn có thể rời đi.” Một thẻ job đơn giản trong trang Imports hoạt động tốt:

  • Upload received: “File uploaded. Validating columns...”
  • Queued: “Waiting for an available worker (2 jobs ahead).”
  • Running: “Importing customers: 3,180 of 8,420 processed (38%).”
  • Wrapping up: “Saving results and building a report... ”

Trong khi chạy, hiển thị một con số tiến trình người dùng có thể tin (số dòng đã xử lý) và một dòng trạng thái ngắn (đang làm gì). Nếu người dùng điều hướng đi, giữ job hiển thị trong khu vực Recent jobs.

Thêm lỗi từng phần. Khi job kết thúc, tránh banner Failed đáng sợ nếu phần lớn dòng ổn. Dùng Finished with issues cùng phân tách rõ:

Imported 8,102 customers. Skipped 318 rows.

Giải thích những nguyên nhân hàng đầu bằng lời đơn giản: định dạng email không hợp lệ, thiếu trường bắt buộc như company, hoặc trùng external ID. Cho phép người dùng tải xuống hoặc xem bảng lỗi với số dòng, tên khách hàng và trường cần sửa.

Retry nên cảm giác an toàn và cụ thể. Hành động chính có thể là Retry failed rows, tạo job mới chỉ xử lý 318 dòng đã bỏ qua sau khi người dùng sửa CSV. Giữ job gốc ở chế độ chỉ đọc để lịch sử trung thực.

Cuối cùng, làm cho kết quả dễ tìm lại. Mỗi import nên có tóm tắt ổn định: ai chạy, khi nào, tên file, số lượng (imported, skipped), và cách mở báo cáo lỗi.

Sai lầm phổ biến khiến tiến trình và retry gây bối rối

Cách nhanh nhất để mất niềm tin là hiển thị số không thực. Thanh tiến trình đứng 0% hai phút rồi nhảy lên 90% tạo cảm giác đoán mò. Nếu bạn không biết phần trăm thực, hiển thị bước (Queued, Processing, Finalizing) hoặc “X of Y items processed.”

Vấn đề khác là tiến trình chỉ lưu trong memory. Nếu worker restart, UI “quên” job hoặc reset tiến trình. Lưu trạng thái trong kho bền và khiến UI đọc từ một nguồn sự thật duy nhất.

UX retry hỏng khi người dùng có thể khởi tạo cùng job nhiều lần. Nếu nút Import CSV vẫn active, ai đó nhấp hai lần và tạo trùng lặp. Khi đó retry không rõ ràng vì không biết sửa run nào.

Những lỗi lặp lại:

  • phần trăm giả không phản ánh công việc thực
  • dump lỗi kỹ thuật hiện ra cho end user (stack trace, mã lỗi)
  • không xử lý timeout, duplicate, hoặc idempotency
  • retry tạo job mới mà không giải thích điều gì xảy ra
  • cancel chỉ thay đổi UI, không ảnh hưởng worker

Một chi tiết nhỏ nhưng quan trọng: tách thông điệp người dùng và chi tiết developer. Hiển thị “12 rows failed validation” cho người dùng, giữ trace kỹ thuật trong logs.

Checklist nhanh trước khi phát hành tác vụ nền cho người dùng

Xây dựng ứng dụng hoàn chỉnh, không chỉ spinner
Tạo backend, web UI và app native xung quanh các tác vụ chạy dài trong AppMaster.
Bắt đầu xây dựng

Trước khi release, kiểm tra nhanh các phần người dùng thấy: rõ ràng, tin cậy và phục hồi.

Mỗi job nên lộ một snapshot bạn có thể hiển thị ở đâu cũng được: state (queued, running, succeeded, failed, canceled), progress (0-100 hoặc steps), một thông điệp ngắn, timestamps (created, started, finished), và một pointer kết quả (nơi lưu output hoặc report).

Làm cho trạng thái UI rõ và nhất quán. Người dùng cần một chỗ đáng tin để tìm job hiện tại và quá khứ, cùng nhãn rõ khi họ quay lại ("Completed yesterday", "Still running"). Một panel Recent jobs thường ngăn việc nhấp lại và làm trùng.

Định nghĩa quy tắc cancel và retry bằng ngôn ngữ dễ hiểu. Quyết định Cancel nghĩa là gì với từng loại job, retry có cho phép không, và tái sử dụng gì (cùng input hay job ID mới). Rồi test các edge case như hủy ngay trước khi hoàn tất.

Đối xử thất bại từng phần như một kết quả thực. Hiển thị tóm tắt ngắn (“Imported 97, skipped 3”) và cung cấp báo cáo hành động người dùng có thể dùng ngay.

Lập kế hoạch phục hồi. Job nên tồn tại qua restart, và job kẹt nên timeout vào trạng thái rõ ràng kèm hướng dẫn ("Try again" hoặc "Contact support with job ID").

Bước tiếp theo: triển khai một workflow rồi mở rộng

Chọn một workflow người dùng đã phàn nàn: import CSV, export báo cáo, gửi email hàng loạt, hoặc xử lý ảnh. Bắt đầu nhỏ và chứng minh cơ bản: job được tạo, chạy, báo trạng thái, và người dùng tìm được sau.

Một màn hình lịch sử job đơn giản thường là bước cải thiện lớn nhất. Nó cho người dùng chỗ quay lại thay vì nhìn spinner mãi.

Chọn một phương thức truyền tiến trình trước. Polling ổn cho phiên bản đầu. Chọn khoảng làm mới đủ chậm để tử tế với backend, nhưng đủ nhanh để cảm thấy sống.

Thứ tự triển khai thực tế tránh phải viết lại:

  • triển khai trạng thái job và chuyển đổi trước (queued, running, succeeded, failed, finished-with-errors)
  • thêm màn hình lịch sử job với bộ lọc cơ bản (24 giờ gần nhất, chỉ job của tôi)
  • thêm số liệu tiến trình chỉ khi bạn chắc nó trung thực
  • thêm hủy chỉ khi bạn đảm bảo cleanup nhất quán
  • thêm retry chỉ khi job idempotent

Nếu bạn xây dựng mà không viết code, nền tảng no-code như AppMaster có thể giúp bằng cách cho bạn mô hình bảng trạng thái job (PostgreSQL) và cập nhật từ workflow, rồi render trạng thái đó trên web và mobile. Với các đội muốn một nơi duy nhất để xây backend, UI và logic nền, AppMaster (appmaster.io) được thiết kế cho ứng dụng toàn diện, không chỉ forms hay trang.

Câu hỏi thường gặp

Sự khác nhau giữa một request chậm và một công việc nền thực sự là gì?

Một công việc nền khởi tạo ngay và trả về một job ID ngay lập tức, nên UI vẫn dùng được. Một request chậm buộc người dùng phải chờ cùng một cuộc gọi web kết thúc, dẫn đến reload, nhấp đôi và gửi trùng lặp.

Tôi nên hiển thị những trạng thái công việc nào cho người dùng?

Giữ đơn giản: queued, running, donefailed, cộng canceled nếu bạn hỗ trợ hủy. Thêm một kết quả riêng như “done with issues” khi phần lớn công việc thành công nhưng có vài mục lỗi, để người dùng không nghĩ mọi thứ bị mất.

Làm sao để đảm bảo người dùng không mất tác vụ khi họ refresh trang?

Trả về một job ID duy nhất ngay sau khi người dùng bắt đầu hành động, rồi hiển thị một hàng hoặc thẻ nhiệm vụ dùng ID đó. UI nên đọc trạng thái theo job ID để người dùng có thể refresh, chuyển tab hoặc quay lại sau mà không mất dấu.

Tiến trình công việc nên được lưu ở đâu để tồn tại qua crash và restart?

Lưu trạng thái công việc vào bảng cơ sở dữ liệu bền (không chỉ trong memory). Ghi lại trạng thái hiện tại, timestamp, giá trị tiến trình, một thông điệp ngắn cho người dùng, và tóm tắt kết quả hoặc lỗi để UI luôn có thể dựng lại cùng một view sau khi khởi động lại.

Khi nào nên dùng progress theo phần trăm so với theo bước?

Chỉ dùng phần trăm khi bạn thực sự có thể báo “X của Y” mục đã xử lý. Nếu không có mẫu số rõ ràng, hiển thị tiến trình theo bước như “Validating”, “Importing”, “Finalizing” và liên tục cập nhật thông điệp để người dùng thấy là có tiến triển.

Tôi nên dùng polling hay push để cập nhật tiến trình trong UI?

Polling là đơn giản nhất và phù hợp hầu hết trường hợp; bắt đầu ở khoảng 2–5 giây khi người dùng đang theo dõi, rồi giảm tần suất cho tác vụ dài hoặc tab nền. Push cho cảm giác tức thời hơn, nhưng luôn cần fallback vì kết nối có thể rớt.

UI nên làm gì nếu tiến trình ngừng cập nhật?

Hiển thị rằng cập nhật đã cũ thay vì giả vờ rằng công việc vẫn hoạt động, ví dụ “Last updated 2 minutes ago” và cung cấp nút refresh thủ công. Ở backend, phát hiện heartbeat mất và chuyển công việc sang trạng thái rõ ràng kèm hướng dẫn, như thử lại hoặc liên hệ support kèm job ID.

Tiến trình tác vụ chạy dài nên xuất hiện ở đâu trong UI?

Cho người dùng biết hành động tiếp theo: họ có thể tiếp tục làm việc, rời trang hay hủy an toàn. Với tác vụ dài hơn một phút, một view Jobs hoặc Activity giúp người dùng tìm kết quả sau này thay vì chờ một spinner duy nhất.

Làm sao báo “hoàn tất với lỗi” mà không làm người dùng hoảng?

Đối xử như một kết quả bình thường và nói rõ cả hai phần, ví dụ “Imported 9,380 of 9,500. 120 failed.” Sau đó cung cấp tóm tắt lỗi ngắn, có thể hành động, để người dùng sửa ngay mà không cần đọc log kỹ thuật; giữ chi tiết kỹ thuật trong log nội bộ.

Làm sao để triển khai hủy và thử lại mà không gây trùng lặp hay nhầm lẫn?

Xác định ý nghĩa của Cancel cho từng loại công việc và phản ánh chính xác trong UI, bao gồm trạng thái trung gian “cancel requested” để người dùng không nhấp liên tục. Làm cho thao tác idempotent khi có thể, giới hạn số retry, và quyết định liệu retry là tiếp tục cùng job hay tạo job mới với audit trail sạch.

Dễ dàng bắt đầu
Tạo thứ gì đó tuyệt vời

Thử nghiệm với AppMaster với gói miễn phí.
Khi bạn sẵn sàng, bạn có thể chọn đăng ký phù hợp.

Bắt đầu