הבלוג של גרי רשף

04/01/2012

Service Broker – דוגמה ליישום

Filed under: Uncategorized — גרי רשף @ 21:07

ברוב הדוגמאות של Service Broker (להלן SB) שניתן לפגוש במאמרים שונים, Tutorials, והרצאות- נותנים דוגמה כיצד מעבירים הודעות בין שני Services: מגדירים אובייקטים (Message Type, Contract, Queue וכו'), שולחים הודעת Hello World דרך חלון ה-SSMS, פותחים חלון נוסף בו מושכים את ההודעה ושולחים הודעת תגובה, וכו':

clip_image001
Queue הוא תור של הודעות, דומה קצת לטבלה.
Contract מאפשר להעביר הודעות מהסוג שהוגדר ב-Message Type (ניתן להגדיר מספר Message Types לכל Contract).
Service יוצר קשר בין Queue ל-Contract, או לחילופין- Contract יוצר קשר בין Queues דרך ה-Services שלהם (ניתן להגדיר מספר Contracts בכל Service ל-Queue אחד). הקשר נוצר ביצירת ה-Service בו מוגדר Queue אחד ומספר כלשהו של Contracts.
העברת הודעה מ-Service 1 ל-Queue 2 נעשית בעזרת Dialog שנפתח בפרוצדורה ששולחת אותה, ונסגר בפרוצדורה שמקבלת אותה (את ההודעה).
כדאי לעיין בפוסטים שמצויינים בהמשך כדי לראות איך פקודות ה-Create השונות של האובייקטים נראות, וכן כיצד מנוהל ה-Dialog.

לא התעסקתי מעולם עם היכולות האלו, במבט ראשון לא כל כך ברור על מה המהומה – הרי הייתי יכול לממש אותו הדבר עם טבלה, אבל במחשבה שנייה אני מבין שזו תשתית שמאפשרת תקשורת יעודית עם יכולות ספציפיות ולא סתם לשלוח הודעות סתמיות בין שני Services.
מה שכן עניין אותי הוא יכולת פחות מוכרת של ה-SB להפעיל פרוצדורה ב"צד השני": במקום לשלוח הודעה ולהמתין שבצד השני ימשכו אותה, נשלח הודעה שתפעיל פרוצדורה; כלומר- אנחנו נדחוף במקום שהם ימשכו..
לי הדבר פתר בעייה ישנה שבעבר פתרתי אותה עם Jobs של הפעלה אסינכרונית של פרוצדורות, כלומר- היכולת להפעיל פרוצדורה ולאפשר לקוד להמשיך הלאה במקביל מבלי להמתין שהריצה שלה תסתיים. אינני יודע אם זו הייתה "כוונת המשורר" – לגבי ג'ובים הם בוודאי לא נועדו לכך, ולגבי SB- אינני יודע.
בכל מקרה- ל-SB יש יתרון בולט על פני שימוש בג'וב להרצה אסינכרונית בכך שהוא מאפשר כמה ריצות במקביל, בעוד שהג'וב לא (ג'וב לא יכול להיות מופעל בו זמנית עם עצמו בניגוד לפרוצדורה באופן כללי או כפי שציינתי- כזו שמופעלת דרך SB).

לפני למעלה משנתיים פרסמתי פוסט בנושא ב-http://www.sqlserver.co.il (ומאוחר יותר גם אצלי בבלוג), והנה נקרתה לי ההזדמנות להשתמש בזה: במקום העבודה שלי יש תהליכים שונים שרצים ואשר מופעלים על ידי פרוצדורה מרכזית שמקבלת כפרמטר את מספר התהליך. יש מספר מפתחים עם הרשאות אדמיניסטרטור, משיקולים ברורים רוצים לצמצם את ההרשאות למינימום ההכרחי, ובין היתר לא לאפשר הפעלה ישירה של הפרוצדורה בסביבות הפיתוח והבדיקות. הפתרון שהוצע היה ליצור טבלה לתוכה כל מפתח יזין את מספר התהליך שברצונו להריץ, ובמקביל יופעל ג'וב כל מספר דקות שיקרא שורה לא מטופלת מהטבלה, ויפעיל את התהליך (כרגע לא משנה מה הרוויחו בכך שחסמו את הגישה לפרוצדורה ואפשרו גישה לטבלה).
החסרון הוא כמובן שצריך להמתין מספר דקות עד שהג'וב יפעיל את התהליך, ולעיתים – אם הג'וב רץ בדיוק על תהליך ארוך יותר – הרבה יותר זמן.
הצעתי להשתמש ב-SB ובניתי מערכת שהתבססה פחות או יותר על הדוגמה מהפוסט, כמובן- עם השינויים הנדרשים.
כצפוי- במציאות נוצרות בעיות שלא תמיד חושבים עליהן כשבונים דוגמה סטרילית עבור פוסט, ואלו העיקריות:

קינפוג– כדי לקנפג את הדטבייס באופן חד פעמי לשימוש ב-SB (על ידי Alter Database MyDatabase Set Enable_Broker;) יש לנתק את כולם ממנו.

פרמטרים– ב-Queue המקבל (MyTargetQueue) הוגדרה הפרוצדורה שצריכה להיות מופעלת כשדוחפים לו הודעה, אבל לא ניתן להעביר לה פרמטרים. הבעייה נפתרה על ידי כך שהפרמטרים נכללו בתור XML בהודעה שנשלחה (בפוסט אצלי בבלוג הדגמתי כיצד לשלוף אותם מה-XML בפרוצדורה P_MySrvBrkProc).

הרשאות– למפתחים יש הרשאות רק להכנסת נתונים לטבלה, וליתר דיוק- להפעלת פרוצדורה שמכניסה שורה לטבלה, ומעבירה Message לצד השני (שגורם לפרוצדורת היעד P_MySrvBrkProc הנ"ל להיות מופעלת באופן אסינכרוני).
פרוצדורת היעד מופעלת על ידי המערכת עם הרשאות Owner (dbo בדרך כלל) כפי שהוגדר ב- MyTargetQueueהמקבל.
למפתח אין הרשאות להפעיל אותה.

Trace– כשמריצים פרוצדורה רוצים לראות את הפלט שלה (פקודות Print לצורך מעקב שכלולות בה, הודעות שגיאה וכו') – בעיקר בשלב הפיתוח, אבל לא רק. לו היינו מפעילים אותה כמתוכנן מלכתחילה דרך ג'וב – ניתן היה להפנות את הפלט לקובץ, אך מה נעשה כשהפרוצדורה מופעלת על ידי SB "מאחורי הקלעים"?
הפתרון שנמצא היה להפעיל אותה דרך שורת הפקודה בעזרת SQLCmd ולהפנות את הפלט לקובץ, כאשר ה-SQLCmd עצמו הופעל בעזרת XP_CmdShell (הפקודה נבנית בתוך פרוצדורת היעד בעזרת הפרמטרים שהועברו אליה):

Exec XP_CmdShell 'sqlcmd -E -S MyServer -d MyDatabase -Q "Exec MyDatabase.dbo.MyProcedure @MyVariable=1;" > C:\MyLogDir\MyLogFile.txt';
Go

כלומר- פרוצדורת היעד אינה זו שמפעילה את התהליך, אלא פרוצדורה ש"עוטפת" את הפרוצדורה שמפעילה את התהליך ומפעילה אותה בעזרת XP_CmdShell ו-SQLCmd עם הפרמטרים שהועברו ב-Message.

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

מודעות פרסומת

להגיב »

עדיין אין תגובות.

RSS feed for comments on this post. TrackBack URI

להשאיר תגובה

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

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s

יצירה של אתר חינמי או בלוג ב־WordPress.com.

%d בלוגרים אהבו את זה: