מבוא לקוורץ

1. סקירה כללית

קְוָרץ היא מסגרת לתזמון עבודות קוד פתוח שנכתבה כולה ב- Java ומיועדת לשימוש בשניהם J2SE ו J2EE יישומים. הוא מציע גמישות רבה מבלי לוותר על הפשטות.

ניתן ליצור לוחות זמנים מורכבים לביצוע כל עבודה. דוגמאות הן למשל משימות שפועלות מדי יום, כל יום שישי אחר בשעה 19:30. או רק ביום האחרון של כל חודש.

במאמר זה נבחן אלמנטים לבניית עבודה עם ממשק ה- API של קוורץ. להקדמה בשילוב עם אביב, אנו ממליצים על תזמון באביב עם קוורץ.

2. תלות Maven

עלינו להוסיף את התלות הבאה ל- pom.xml:

 org.quartz-scheduler quartz 2.3.0 

ניתן למצוא את הגרסה האחרונה במאגר Maven Central.

3. ממשק ה- API של קוורץ

לב המסגרת הוא מתזמן. היא אחראית על ניהול סביבת זמן הריצה ליישום שלנו.

כדי להבטיח יכולת הרחבה, קוורץ מבוסס על ארכיטקטורה מרובת-הברגה. כאשר התחילה, המסגרת מאותטחת קבוצה של שרשורי עובדים המשמשים את מתזמן להוציא להורג מקומות תעסוקה.

כך המסגרת יכולה לרוץ רבות מקומות תעסוקה במקביל. זה מסתמך גם על קבוצה משולבת של ThreadPool רכיבי ניהול לניהול סביבת השרשור.

ממשקי המפתח של ה- API הם:

  • מתזמן - ה- API העיקרי לאינטראקציה עם מתזמן המסגרת
  • עבודה - ממשק שיושם על ידי רכיבים שברצוננו לבצע
  • JobDetail - משמש להגדרת מקרים של עבודהס
  • הדק - רכיב הקובע את לוח הזמנים לפיו נתון עבודה יבוצע
  • JobBuilder - נהג לבנות JobDetail מקרים, המגדירים מקרים של מקומות תעסוקה
  • TriggerBuilder - נהג לבנות הדק מקרים

בואו נסתכל על כל אחד מאותם רכיבים.

4. מתזמן

לפני שנוכל להשתמש ב- מתזמן, זה צריך להיות מיידי. לשם כך אנו יכולים להשתמש במפעל SchedulerFactory:

SchedulerFactory schedulerFactory = StdSchedulerFactory חדש (); מתזמן מתזמן = schedulerFactory.getScheduler ();

א מתזמןמחזור חייו מוגבל ביצירתו, דרך א SchedulerFactory וקריאה ל לכבות() שיטה. ברגע שיצר את מתזמן ניתן להשתמש בממשק להוספה, הסרה ורשימה מקומות תעסוקה ו טריגרים, ובצע פעולות אחרות הקשורות לתזמון (כגון השהיית טריגר).

למרות זאת, ה מתזמן לא יפעל על שום טריגרים עד שזה התחיל עם ה- הַתחָלָה() שיטה:

scheduler.start ();

5. משרות

א עבודה הוא מחלקה המיישמת את עבודה מִמְשָׁק. יש לה רק שיטה אחת פשוטה:

מחלקה ציבורית מיישמת SimpleJob את Job {public void execute (JobExecutionContext arg0) זורק את JobExecutionException {System.out.println ("זו עבודה קוורץ!"); }}

כאשר מקומות תעסוקה להפעיל שריפות, לבצע() השיטה מופעלת על ידי אחד מחוטי העובד של המתזמן.

ה JobExecutionContext אובייקט המועבר לשיטה זו מספק למופע העבודה, מידע על סביבת זמן הריצה שלו, אחיזה ל- מתזמן שביצע את זה, ידית ל הדק שגרם לביצוע, לתפקיד JobDetail אובייקט, ועוד כמה פריטים.

ה JobDetail האובייקט נוצר על ידי לקוח קוורץ בזמן בו עבודה מתווסף ל מתזמן. זו בעצם ההגדרה של מקרה העבודה:

JobDetail job = JobBuilder.newJob (SimpleJob.class) .withIdentity ("myJob", "group1") .build ();

אובייקט זה עשוי להכיל גם הגדרות מאפיין שונות עבור ה- עבודה, כמו גם א JobDataMap, אשר יכול לשמש לאחסון מידע ממלכתי למופע נתון של מעמד העבודה שלנו.

5.1. JobDataMap

ה JobDataMap משמש להחזקת כל כמות של אובייקטים נתונים שברצוננו להעמיד לרשות מופע העבודה בעת ביצועו. JobDataMap הוא יישום של Java מַפָּה ממשק ויש לו כמה שיטות נוחות לאחסון ואחזור נתונים מסוגים פרימיטיביים.

הנה דוגמה להכנסת נתונים ל JobDataMap תוך כדי בניית ה- JobDetailלפני הוספת המשרה למתזמן:

JobDetail job = newJob (SimpleJob.class) .withIdentity ("myJob", "group1") .usingJobData ("jobSays", "שלום עולם!") .UsingJobData ("myFloatValue", 3.141f) .build ();

והנה דוגמה כיצד לגשת לנתונים אלה במהלך ביצוע העבודה:

מחלקה ציבורית SimpleJob מיישם את Job {public void execute (JobExecutionContext context) זורק את JobExecutionException {JobDataMap dataMap = context.getJobDetail (). getJobDataMap (); מחרוזת jobSays = dataMap.getString ("jobSays"); צף myFloatValue = dataMap.getFloat ("myFloatValue"); System.out.println ("איוב אומר:" + jobSays + ", ו- val הוא:" + myFloatValue); }}

הדוגמה לעיל תדפיס "איוב אומר שלום עולם !, וערך הוא 3.141".

אנו יכולים גם להוסיף שיטות קביעה למחלקת התפקידים שלנו שתואמות את שמות המפתחות ב- JobDataMap.

אם נעשה זאת, ברירת המחדל של קוורץ JobFactory היישום מכנה באופן אוטומטי את אותם מגדירים כאשר העבודה מופעלת באופן מיידי, ובכך מונע את הצורך להוציא במפורש את הערכים מהמפה בשיטת הביצוע שלנו.

6. טריגרים

הדק אובייקטים משמשים להפעלת הביצוע של מקומות תעסוקה.

כשאנחנו רוצים לתזמן א עבודה, עלינו להפעיל טריגר ולהתאים את המאפיינים שלו כדי להגדיר את דרישות התזמון שלנו:

טריגר טריגר = TriggerBuilder.newTrigger () .withIdentity ("myTrigger", "group1") .startNow () .withSchedule (SimpleScheduleBuilder.simpleSchedule () .withIntervalInSeconds (40) .repeatForever ()). בניין ();

א הדק יכול להיות גם שיש JobDataMap קשור אליו. זה שימושי להעברת פרמטרים ל- a עבודה ספציפיים לביצוע ההדק.

ישנם סוגים שונים של טריגרים לצרכי תזמון שונים. לכל אחד יש שונה טריגרקיי נכסים למעקב אחר זהותם. עם זאת, כמה מאפיינים אחרים משותפים לכל סוגי ההדק:

  • ה jobKey המאפיין מציין את זהות העבודה שצריך לבצע כאשר הדק יורה.
  • ה שעת התחלה מאפיין מציין מתי לוח הזמנים של הדק נכנס לתוקף לראשונה. הערך הוא a java.util.Date אובייקט שמגדיר רגע בזמן לתאריך קלנדרי נתון. עבור סוגים מסוימים של טריגר, ההדק יופעל בזמן ההתחלה הנתון. עבור אחרים, זה פשוט מסמן את הזמן שבו לוח הזמנים אמור להתחיל.
  • ה endTime המאפיין מציין מתי יש לבטל את לוח הזמנים של הדק.

ספינות קוורץ עם קומץ סוגי טריגר שונים, אבל הנפוצים ביותר הם SimpleTrigger ו CronTrigger.

6.1. עדיפות

לפעמים, כשיש לנו הרבה טריגרים, ייתכן שקוורץ לא יהיה מספיק משאבים לפטר מיד את כל העבודות המתוכננות להתפטר בו זמנית. במקרה זה, ייתכן שנרצה לשלוט אילו מהטריגרים שלנו יהיו זמינים תחילה. זה בדיוק מה ש עדיפות משמש עבור מאפיין על ההדק.

לדוגמה, כאשר עשרה טריגרים מוגדרים בו זמנית ורק ארבעה שרשורי עובדים זמינים, ארבעת הטריגרים הראשונים בעלי העדיפות הגבוהה ביותר יבוצעו תחילה. כאשר אנו לא קובעים עדיפות על טריגר, הוא משתמש בעדיפות ברירת מחדל של חמש. כל ערך שלם מותר כעדיפות, חיובי או שלילי.

בדוגמה שלהלן, יש לנו שני טריגרים בעלי עדיפות שונה. אם אין מספיק משאבים לפטר את כל הטריגרים בו זמנית, טריגר A. יהיה הראשון שפוטר:

טריגר triggerA = TriggerBuilder.newTrigger () .withIdentity ("triggerA", "group1") .startNow () .withPriority (15) .withSchedule (SimpleScheduleBuilder.simpleSchedule () .withIntervalInSeconds (40) .repeatForever (). ; טריגר טריגר B = TriggerBuilder.newTrigger () .withIdentity ("triggerB", "group1") .startNow () .withPriority (10) .withSchedule (SimpleScheduleBuilder.simpleSchedule () .withIntervalInSeconds (20). RepeatForever (). ;

6.2. הוראות Misfire

אש שגויה מתרחשת אם גורם מתמשך מתגעגע זמן הירי שלה בגלל מתזמן בכיבוי, או במקרה שאין חוטים זמינים במאגר החוטים של קוורץ.

לסוגי הדק השונים יש הוראות שונות להטעות אש. כברירת מחדל, הם משתמשים בהוראות מדיניות חכמה. כאשר המתזמן מתחיל, הוא מחפש אחר טריגרים מתמשכים שלא אושרו כהלכה. לאחר מכן, הוא מעדכן כל אחד מהם בהתבסס על הוראות ההטעיה השגויה שלהם.

בואו נסתכל על הדוגמאות הבאות:

טריגר misFiredTriggerA = TriggerBuilder.newTrigger () .startAt (DateUtils.addSeconds (תאריך חדש (), -10)) .build (); טריגר misFiredTriggerB = TriggerBuilder.newTrigger () .startAt (DateUtils.addSeconds (תאריך חדש (), -10)). WithSchedule (SimpleScheduleBuilder.simpleSchedule () .withMisfireHandlingInstructionFireNow ()). בניין ();

קבענו שהטריגר יפעל לפני 10 שניות (כך שהוא מאחר ב -10 שניות עד שנוצר) כדי לדמות אש שגויה, למשל. מכיוון שהמתזמן לא היה או שאין כמות מספקת של שרשור עובדים. כמובן, בתרחיש של העולם האמיתי, לעולם לא נקבע טריגרים כאלה.

בטריגר הראשון (misFiredTriggerA) לא נקבעו הוראות לטיפול בטעות באש. מכאן נקרא מדיניות חכמה משמש במקרה זה ונקרא: withMisfireHandlingInstructionFireNow (). המשמעות היא שהמשימה מבוצעת מיד לאחר שמתזמן מגלה את האש שגויה.

הטריגר השני מגדיר במפורש לאיזה סוג של התנהגות אנו מצפים כאשר מתרחשת אי-טעות. בדוגמה זו, פשוט במקרה מדובר באותה מדיניות חכמה.

6.3. SimpleTrigger

SimpleTrigger משמש לתרחישים בהם אנו צריכים לבצע עבודה ברגע מסוים בזמן. זה יכול להיות בדיוק פעם אחת או שוב ושוב במרווחים ספציפיים.

דוגמה יכולה להיות לפטר ביצוע עבודה בדיוק בשעה 12:20:00 ב -13 בינואר 2018. באופן דומה, אנו יכולים להתחיל באותה שעה, ואז חמש פעמים נוספות, כל עשר שניות.

בקוד שלמטה, התאריך myStartTime הוגדר בעבר ומשמש לבניית טריגר לחותמת זמן מסוימת:

טריגר SimpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger () .withIdentity ("trigger1", "group1") .startAt (myStartTime) .forJob ("job1", "group1") .build ();

לאחר מכן, בואו לבנות טריגר לרגע מסוים בזמן, ואז לחזור על כל עשר שניות עשר פעמים:

הדק SimpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger () .withIdentity ("trigger2", "group1") .startAt (myStartTime) .withSchedule (simpleSchedule () .withIntervalInSeconds (10) .withRepeatCount (10)). "ForJob (" job) ". ) .בניין ();

6.4. CronTrigger

ה CronTrigger משמש כאשר אנו זקוקים ללוחות זמנים המבוססים על הצהרות דומות ליומן. לדוגמא, אנו יכולים לציין לוחות זמנים לירי כגון בכל יום שישי בצהריים אוֹ בכל יום חול בשעה 9:30 בבוקר.

ביטויים של Cron משמשים להגדרת תצורה של מופעים CronTrigger. ביטויים אלה מורכבים מ מיתרים המורכבים משבעה ביטויי משנה. אנו יכולים לקרוא עוד על Cron- ביטויים כאן.

בדוגמה שלהלן אנו בונים טריגר שיורה כל דקה אחרת בין השעות 8: 00-17: 00, כל יום:

CronTrigger trigger = TriggerBuilder.newTrigger () .withIdentity ("trigger3", "group1") .withSchedule (CronScheduleBuilder.cronSchedule ("0 0/2 8-17 * *?")). ForJob ("myJob", "group1" ) .בניין ();

7. מסקנה

במאמר זה הראינו כיצד לבנות a מתזמן להפעיל א עבודה. ראינו גם כמה מאפשרויות ההדק הנפוצות ביותר: SimpleTrigger ו CronTrigger.

ניתן להשתמש בקוורץ ליצירת לוחות זמנים פשוטים או מורכבים לביצוע עשרות, מאות ואפילו יותר עבודות. מידע נוסף על המסגרת ניתן למצוא באתר הראשי.

קוד המקור של הדוגמאות ניתן למצוא באתר GitHub.