Πώς να Εκτελέσετε Εργασίες Παρασκηνίου στο ASP.NET Core

Εισαγωγή

Η επεξεργασία αρχείων (π.χ., εξαγωγή μιας παρουσίασης σε PDF) είναι μια τυπική εργασία από την πλευρά του διακομιστή. Η εκτέλεσή της μέσα στον διαχειριστή αιτήματος (ενώ ο πελάτης περιμένει) έχει τα παρακάτω μειονεκτήματα:

  • Κακή διεπαφή χρήστη. Η σελίδα παγώνει και ο χρήστης πρέπει να περιμένει το αποτέλεσμα. Η επαναφόρτωση της σελίδας ακυρώνει την εργασία.
  • Λήξη χρόνου λειτουργίας. Δεν μπορούμε να εξασφαλίσουμε ότι η επεξεργασία θα ολοκληρωθεί εντός σταθερού χρονικού διαστήματος, οπότε είναι πιθανό ο χρήστης να δει ένα «operation timeout».
  • Χαμηλή απόδοση και επεκτασιμότητα. Το ASP.NET Core σχεδιάστηκε για την επεξεργασία πολλών αιτημάτων ασύγχρονα. Εργασίες που απαιτούν CPU και διαρκούν πολύ χρόνο μπλοκάρουν νήματα και μειώνουν την απόδοση του διακομιστή.
  • Κακή ανθεκτικότητα σε σφάλματα. Αν κάτι πάει λάθος κατά τη διάρκεια μιας μακράς εργασίας (π.χ., πρόβλημα συνδεσιμότητας), η επεξεργασία αποτυγχάνει και πρέπει να ξεκινήσει ξανά από την αρχή.

Μια καλύτερη προσέγγιση είναι να προγραμματίζετε τη δουλειά ασύγχρονα, να την επεξεργάζεστε στο παρασκήνιο και να επιστρέφετε το αποτέλεσμα όταν είναι έτοιμο.

Σε αυτό το μοντέλο, ο χρήστης μπορεί να δει την τρέχουσα κατάσταση (και μπορεί να φύγει ή να ξαναφορτώσει τη σελίδα), οι πόροι του διακομιστή μπορούν να κλιμακωθούν αποδοτικά και να ρυθμιστούν ευέλικτα, και μπορεί να εφαρμοστεί μια πολιτική επαναπροσπροσπάθειας.

Μια τυπική λύση επεξεργασίας στο παρασκήνιο περιλαμβάνει:

  1. Ένα API για τον προγραμματισμό της εργασίας.
  2. Ένα API για την παρακολούθηση της κατάστασης της εργασίας.
  3. Ένα παρασκήνιο εργαζόμενο (background worker) για την επεξεργασία των προγραμματισμένων εργασιών.
  4. Ένα API για την αποθήκευση και ανάκτηση του αποτελέσματος.

Παράδειγμα Εργασίας Παρασκηνίου

Για να δείξετε αυτήν την προσέγγιση, εξετάστε τη δείγμα εφαρμογής web ASP.NET Core 3.1. Η εφαρμογή περιλαμβάνει μια σελίδα όπου ο χρήστης μπορεί να ανεβάσει μια παρουσίαση και να κάνει κλικ στο Export to PDF· η παρουσίαση ανεβαίνει και μετατρέπεται σε PDF από έναν background worker.

Εφαρμογή Web

Η δείγματική web εφαρμογή (πρότζεκτ BackgroundJobDemo) περιλαμβάνει:

  • Σελίδα ανεβάσματος αρχείου (Razor page “Upload”).
  • Σελίδα προόδου (Razor page “Progress” με μερικές λειτουργίες JavaScript που ελέγχουν και εμφανίζουν την κατάσταση).
  • Controller (JobStatusController) που παρέχει την κατάσταση επεξεργασίας (api/status/{jobId}).
  • Controller (JobResultController) που επιστρέφει το εξαχθέν αρχείο PDF (api/result/{id}).
  • Background worker βασισμένος στην υπηρεσία φιλοξενίας του ASP.NET Core (δείτε την κλάση WorkerService).

Οι Razor pages, οι controllers και ο background worker αναθέτουν την πραγματική εργασία μέσω διεπαφών που ορίζονται στο έργο BackgroundJobDemo.Common. Συγκεκριμένες υλοποιήσεις διαχείρισης εργασιών και επεξεργασίας παρέχονται σε ξεχωριστά έργα (BackgroundJobDemo.Local, BackgroundJobDemo.Aws, κ.λπ.) και μπορούν να εναλλαχθούν στη μέθοδο Startup.ConfigureServices.

Για σκοπούς επίδειξης, η σελίδα “Upload” χρησιμοποιεί δεσμευμένη (buffered) σύνδεση μοντέλου, αλλά για μεγάλες μεταφορτώσεις αρχείων συνιστάται η μη δεσμευμένη ροή (unbuffered streaming) συνιστάται. Για παραγωγή, σκεφτείτε τις σχετικές ασφάλειας. Η σελίδα “Progress” ελέγχει (polls) την κατάσταση της προγραμματισμένης εργασίας μέσω JavaScript κάθε δύο δευτερόλεπτα (αυτό το διάστημα είναι ρυθμιζόμενο). Η χρησιμοποίηση polling είναι τυπική, αλλά για πιο προχωρημένα σενάρια μπορεί να χρειάζεστε ειδοποιήσεις σε πραγματικό χρόνο μέσω WebSockets (οι επικοινωνίες σε πραγματικό χρόνο είναι εκτός πεδίου αυτού του άρθρου). SignalR είναι ένα απλό αλλά ισχυρό εργαλείο για επικοινωνίες σε πραγματικό χρόνο.

Η φιλοξενία του background worker στη διαδικασία του διακομιστή είναι βολική για απλές εφαρμογές αλλά έχει μειονεκτήματα. Μια πιο ανθεκτική και επεκτάσιμη προσέγγιση είναι η ανάπτυξη του worker σε ξεχωριστή διαδικασία (δείτε, π.χ., την κονσολική εφαρμογή BackgroundJobDemo.Worker).

Βασική Υλοποίηση

Το έργο BackgroundJobDemo.Local παρέχει μια απλή υλοποίηση διαχείρισης εργασιών χρησιμοποιώντας μια βάση δεδομένων SQLite (η διαδρομή της βάσης ρυθμίζεται μέσω LocalConfig.DbFilePath; δείτε Startup.ConfigureServices). Τα ανεβασμένα και επεξεργασμένα αρχεία αποθηκεύονται στο σύστημα αρχείων (η διαδρομή του φακέλου αποθήκευσης ρυθμίζεται μέσω LocalConfig.FileStorageFolderPath; δείτε Startup.ConfigureServices). Για καλύτερη ανθεκτικότητα σε σφάλματα και απόδοση σε πραγματικές εφαρμογές, ο προγραμματισμός εργασιών θα πρέπει να υλοποιηθεί μέσω ουρών μηνυμάτων (π.χ., RabbitMQ, AWS SQS, Azure Storage Queue).

Κατανεμημένη Υλοποίηση Βασισμένη στις Amazon Web Services

Το έργο BackgroundJobDemo.Aws υλοποιεί την επεξεργασία εργασιών στις Amazon Web Services και δείχνει μια οριζόντια κλιμακώσιμη κατανεμημένη αρχιτεκτονική. Περιλαμβάνει τα παρακάτω στοιχεία:

  • Web app — αλληλεπιδρά με τον χρήστη και προγραμματίζει εργασίες εξαγωγής PPTX‑σε‑PDF κ.ά.
  • Worker — επεξεργάζεται τις εξαγωγές (εντός διεργασίας, εκτός διεργασίας ή AWS Lambda).
  • Message queue — αποθηκεύει τις εργασίες προς επεξεργασία (Amazon SQS).
  • File storage — αποθηκεύει τα ανεβασμένα και επεξεργασμένα αρχεία (Amazon S3).
  • Key‑value store — παρακολουθεί την κατάσταση επεξεργασίας της εργασίας (Amazon DynamoDB).

Μια τυπική κατανεμημένη αρχιτεκτονική βασίζεται σε ουρές μηνυμάτων: η web εφαρμογή τοποθετεί εργασίες παρασκηνίου σε μια ουρά· ένας background worker ανακτά εργασίες από την ουρά και εκτελεί τη ζητούμενη εργασία. Αυτό αποσυνδέει τα στοιχεία και κάνει την επεξεργασία ασύγχρονη και αξιόπιστη. Η ουρά εγγυάται την παράδοση και χρησιμοποιεί ένα visibility timeout: όταν ένας worker παίρνει ένα μήνυμα, αυτό γίνεται αόρατο για άλλους workers· μόνο ο worker που επεξεργάζεται το αφαιρεί μετά την ολοκλήρωση. Εάν η επεξεργασία δεν ολοκληρωθεί εντός του visibility timeout (π.χ., λόγω αποτυχίας ή προβλήματος δικτύου), το αμετάβλητο μήνυμα γίνεται ξανά ορατό.

Η υλοποίησή μας χρησιμοποιεί το Amazon Simple Queue Service (SQS), μια πλήρως διαχειριζόμενη ουρά μηνυμάτων για μικροϋπηρεσίες, κατανεμημένα συστήματα και serverless εφαρμογές.

Οι ουρές μηνυμάτων προορίζονται για ελαφριά μηνύματα (π.χ., το όριο μεγέθους μηνύματος του SQS είναι 256 KB), έτσι ένα μήνυμα πρέπει να περιέχει μόνο την περιγραφή της εργασίας. Τα βαριά δεδομένα (όπως αρχεία προς επεξεργασία) πρέπει να αποθηκευτούν ξεχωριστά και να αναφέρονται από το μήνυμα. Το Amazon S3 χρησιμοποιείται για την αποθήκευση των ανεβασμένων και επεξεργασμένων αρχείων.

Απαιτείται ένα κατάστημα κλειδιού‑τιμής (key‑value store) για τη διατήρηση και ανάκτηση των αποτελεσμάτων εργασιών κατά ID. Το παράδειγμα χρησιμοποιεί το Amazon DynamoDB, μια γρήγορη και ευέλικτη υπηρεσία NoSQL βάσης δεδομένων.

Για να εκτελέσετε την εφαρμογή επίδειξης με τις Amazon Web Services:

  1. Στην ίδια περιοχή AWS, δημιουργήστε και διαμορφώστε:
    1. μια ουρά SQS,
    2. ένα bucket S3,
    3. ένα πίνακα DynamoDB.
  2. Συνδέστε την web εφαρμογή με αυτές τις υπηρεσίες καλώντας το AddAws στο Startup.ConfigureServices, παρέχοντας το URL της ουράς SQS, το όνομα του bucket S3, το όνομα του πίνακα DynamoDB και την περιοχή AWS.

Αναφορές