From f1f3d033b1864a189ef78059d8b4d37003be43b9 Mon Sep 17 00:00:00 2001 From: "Quartz.NET" Date: Thu, 3 Mar 2022 21:50:34 +0000 Subject: [PATCH 1/2] Deploy Documentation --- 2012/04/09/quartznet-2-0-released/index.html | 57 ++++ .../04/22/quartznet-2-0-1-released/index.html | 56 ++++ 2012/12/31/quartznet-2-1-released/index.html | 57 ++++ .../01/05/quartznet-2-1-1-released/index.html | 56 ++++ .../01/13/quartznet-2-1-2-released/index.html | 56 ++++ 2013/10/09/quartznet-2-2-released/index.html | 58 ++++ .../11/24/quartznet-2-2-1-released/index.html | 56 ++++ .../06/website-moved-gihub-pages/index.html | 55 ++++ .../index.html | 56 ++++ .../02/09/quartznet-2-2-2-released/index.html | 57 ++++ .../03/30/quartznet-2-2-3-released/index.html | 58 ++++ .../07/27/quartznet-2-2-4-released/index.html | 56 ++++ 2014/11/08/quartznet-2-3-released/index.html | 56 ++++ .../01/15/quartznet-2-3-1-released/index.html | 57 ++++ .../01/15/quartznet-2-3-2-released/index.html | 56 ++++ .../07/09/quartznet-2-3-3-released/index.html | 56 ++++ .../quartznet-3-0-alpha1-released/index.html | 55 ++++ 2016/08/18/quartznet-2-4-released/index.html | 57 ++++ .../08/24/quartznet-2-4-1-released/index.html | 57 ++++ .../quartznet-3-0-alpha2-released/index.html | 56 ++++ 2017/02/18/quartznet-2-5-released/index.html | 57 ++++ 2017/07/30/quartznet-2-6-released/index.html | 56 ++++ .../quartznet-3-0-alpha3-released/index.html | 57 ++++ .../quartznet-3-0-beta1-released/index.html | 55 ++++ .../10/09/quartznet-2-6-1-released/index.html | 56 ++++ 2017/12/30/quartznet-3-0-released/index.html | 58 ++++ .../01/21/quartznet-3-0-1-released/index.html | 58 ++++ .../01/25/quartznet-3-0-2-released/index.html | 56 ++++ .../02/24/quartznet-3-0-3-released/index.html | 56 ++++ .../03/04/quartznet-3-0-4-released/index.html | 57 ++++ .../05/27/quartznet-2-6-2-released/index.html | 56 ++++ .../05/27/quartznet-3-0-5-released/index.html | 56 ++++ .../07/06/quartznet-3-0-6-released/index.html | 57 ++++ .../10/07/quartznet-3-0-7-released/index.html | 58 ++++ 2020/07/06/website-refresh/index.html | 55 ++++ .../quartznet-3-1-beta-1-released/index.html | 56 ++++ .../quartznet-3-1-beta-2-released/index.html | 57 ++++ .../quartznet-3-1-beta-3-released/index.html | 63 ++++ 2020/07/21/quartznet-3-1-released/index.html | 55 ++++ 2020/07/24/quartznet-3-1-released/index.html | 68 +++++ 2020/10/01/quartznet-3-2-released/index.html | 105 +++++++ .../10/18/quartznet-3-2-1-released/index.html | 59 ++++ .../10/19/quartznet-3-2-2-released/index.html | 56 ++++ .../10/31/quartznet-3-2-3-released/index.html | 58 ++++ .../01/19/quartznet-3-2-4-released/index.html | 58 ++++ 2021/04/07/quartznet-3-3-released/index.html | 60 ++++ .../04/08/quartznet-3-3-1-released/index.html | 56 ++++ .../04/09/quartznet-3-3-2-released/index.html | 58 ++++ .../08/01/quartznet-3-3-3-released/index.html | 56 ++++ 404.html | 33 +++ android-icon-144x144.png | Bin 0 -> 19676 bytes android-icon-192x192.png | Bin 0 -> 27792 bytes android-icon-36x36.png | Bin 0 -> 3114 bytes android-icon-48x48.png | Bin 0 -> 4487 bytes android-icon-72x72.png | Bin 0 -> 7366 bytes android-icon-96x96.png | Bin 0 -> 11073 bytes apple-icon-114x114.png | Bin 0 -> 14327 bytes apple-icon-120x120.png | Bin 0 -> 15322 bytes apple-icon-144x144.png | Bin 0 -> 19676 bytes apple-icon-152x152.png | Bin 0 -> 21264 bytes apple-icon-180x180.png | Bin 0 -> 26748 bytes apple-icon-57x57.png | Bin 0 -> 5454 bytes apple-icon-60x60.png | Bin 0 -> 5718 bytes apple-icon-72x72.png | Bin 0 -> 7366 bytes apple-icon-76x76.png | Bin 0 -> 7879 bytes apple-icon-precomposed.png | Bin 0 -> 28366 bytes apple-icon.png | Bin 0 -> 28366 bytes assets/css/0.styles.af8ca635.css | 1 + assets/img/search.83621669.svg | 1 + assets/js/10.5459967e.js | 1 + assets/js/100.70eedb6c.js | 1 + assets/js/101.e7dd71b5.js | 1 + assets/js/102.d099ddb5.js | 1 + assets/js/103.4cce09e1.js | 1 + assets/js/104.8a143487.js | 1 + assets/js/105.bbb1e2b5.js | 1 + assets/js/106.8db45d2f.js | 1 + assets/js/107.7ec33075.js | 1 + assets/js/108.428f64db.js | 1 + assets/js/109.60b57a1e.js | 1 + assets/js/11.e2aadbde.js | 1 + assets/js/110.ee5b642d.js | 1 + assets/js/111.5ea56c24.js | 1 + assets/js/112.f9b9113a.js | 1 + assets/js/113.50eb57e0.js | 1 + assets/js/114.5a891d47.js | 1 + assets/js/115.503308f5.js | 1 + assets/js/116.edf242c3.js | 1 + assets/js/117.87d68a22.js | 1 + assets/js/118.1a20ec6b.js | 1 + assets/js/119.5545109a.js | 1 + assets/js/12.632699a6.js | 1 + assets/js/120.ac3b1282.js | 1 + assets/js/121.b9c8a72f.js | 1 + assets/js/122.702d9fad.js | 1 + assets/js/123.b873e59c.js | 1 + assets/js/124.73484c48.js | 1 + assets/js/125.1873365c.js | 1 + assets/js/126.2b8c172b.js | 1 + assets/js/127.ce06c938.js | 1 + assets/js/128.853bfa59.js | 1 + assets/js/129.a07b8371.js | 1 + assets/js/13.c53349db.js | 1 + assets/js/130.0feef69a.js | 1 + assets/js/131.c5fcddc7.js | 1 + assets/js/132.13fbd625.js | 1 + assets/js/133.f3d14f4d.js | 1 + assets/js/134.320abb38.js | 1 + assets/js/135.be16f19a.js | 1 + assets/js/136.de2948c9.js | 1 + assets/js/137.52cca593.js | 1 + assets/js/138.272768ba.js | 1 + assets/js/139.cb00fd64.js | 1 + assets/js/14.6535f905.js | 1 + assets/js/140.e168ce8e.js | 1 + assets/js/141.66280f26.js | 1 + assets/js/142.2f9f56f4.js | 1 + assets/js/143.35b86cf0.js | 1 + assets/js/144.419ebf8f.js | 1 + assets/js/145.4e24e5c4.js | 1 + assets/js/146.ec8464bd.js | 1 + assets/js/15.e0899e5a.js | 1 + assets/js/16.5066eada.js | 1 + assets/js/17.2cd0575f.js | 1 + assets/js/18.729d30ae.js | 1 + assets/js/19.e79f2201.js | 1 + assets/js/20.649245c0.js | 1 + assets/js/21.1a3614c5.js | 1 + assets/js/22.8a66bf8f.js | 1 + assets/js/23.e7ae5d25.js | 1 + assets/js/24.cde296f3.js | 1 + assets/js/25.346eb63b.js | 1 + assets/js/26.4a2442fe.js | 1 + assets/js/27.1ced7f91.js | 1 + assets/js/28.8cf196b8.js | 1 + assets/js/29.d3bbf14c.js | 1 + assets/js/3.836353be.js | 1 + assets/js/30.2285aa3b.js | 1 + assets/js/31.de5c4db1.js | 1 + assets/js/32.35d4940b.js | 1 + assets/js/33.32a324dc.js | 1 + assets/js/34.4cefe782.js | 1 + assets/js/35.3912f4fb.js | 1 + assets/js/36.3b387353.js | 1 + assets/js/37.193bf8a1.js | 1 + assets/js/38.83de4ad0.js | 1 + assets/js/39.9607a50c.js | 1 + assets/js/4.9a469852.js | 1 + assets/js/40.e5ff7906.js | 1 + assets/js/41.7affac67.js | 1 + assets/js/42.00fe8e23.js | 1 + assets/js/43.4f7d0962.js | 1 + assets/js/44.fd58bb75.js | 1 + assets/js/45.07c03278.js | 1 + assets/js/46.6b0f5704.js | 1 + assets/js/47.1b566e3b.js | 1 + assets/js/48.31882e6a.js | 1 + assets/js/49.350a7768.js | 1 + assets/js/5.b59b1de3.js | 1 + assets/js/50.511e3e44.js | 1 + assets/js/51.86078c87.js | 1 + assets/js/52.b04217a8.js | 1 + assets/js/53.d4849106.js | 1 + assets/js/54.568a20d9.js | 1 + assets/js/55.b96bcec3.js | 1 + assets/js/56.6c9b74df.js | 1 + assets/js/57.00f4144b.js | 1 + assets/js/58.816401b6.js | 1 + assets/js/59.39f29e19.js | 1 + assets/js/6.4b03a90b.js | 1 + assets/js/60.65653623.js | 1 + assets/js/61.7418f9a5.js | 1 + assets/js/62.0bc12fc5.js | 1 + assets/js/63.a9ad1d02.js | 1 + assets/js/64.d0324155.js | 1 + assets/js/65.4e9653df.js | 1 + assets/js/66.3e14e87f.js | 1 + assets/js/67.1aade945.js | 1 + assets/js/68.ada97766.js | 1 + assets/js/69.3918d066.js | 1 + assets/js/7.73b42248.js | 1 + assets/js/70.6d54ab0b.js | 1 + assets/js/71.a7334470.js | 1 + assets/js/72.337891b4.js | 1 + assets/js/73.6f58b4eb.js | 1 + assets/js/74.a79659d2.js | 1 + assets/js/75.ac772cc7.js | 1 + assets/js/76.ac780687.js | 1 + assets/js/77.b087b822.js | 1 + assets/js/78.0c35c107.js | 1 + assets/js/79.c0acd288.js | 1 + assets/js/8.d0570d6e.js | 1 + assets/js/80.f966b0e7.js | 1 + assets/js/81.a91e6c4f.js | 1 + assets/js/82.d6972444.js | 1 + assets/js/83.5fb1964c.js | 1 + assets/js/84.11a39734.js | 1 + assets/js/85.7a20170c.js | 1 + assets/js/86.f892a53a.js | 1 + assets/js/87.0a9e471c.js | 1 + assets/js/88.677da331.js | 1 + assets/js/89.52251cd3.js | 1 + assets/js/9.f3852c3d.js | 1 + assets/js/90.88b29d89.js | 1 + assets/js/91.4a66f8db.js | 1 + assets/js/92.46584aef.js | 1 + assets/js/93.e616473a.js | 1 + assets/js/94.8b47a217.js | 1 + assets/js/95.487cae6e.js | 1 + assets/js/96.848a034e.js | 1 + assets/js/97.d11e3968.js | 1 + assets/js/98.1252ce69.js | 1 + assets/js/99.f28f8a22.js | 1 + assets/js/app.78225083.js | 8 + assets/js/vendors~docsearch.eec9cc92.js | 3 + blog | 55 ++++ blog.html | 55 ++++ blogpage/2/index.html | 55 ++++ blogpage/3/index.html | 55 ++++ blogpage/4/index.html | 55 ++++ blogpage/5/index.html | 55 ++++ browserconfig.xml | 2 + documentation/best-practices.html | 71 +++++ documentation/faq.html | 187 ++++++++++++ documentation/index.html | 55 ++++ documentation/quartz-1.x/index.html | 55 ++++ .../advanced-enterprise-features.html | 70 +++++ ...-resource-usage-and-scheduler-factory.html | 94 ++++++ .../quartz-1.x/tutorial/crontriggers.html | 92 ++++++ documentation/quartz-1.x/tutorial/index.html | 55 ++++ .../quartz-1.x/tutorial/job-stores.html | 106 +++++++ .../tutorial/jobs-and-triggers.html | 96 ++++++ .../tutorial/miscellaneous-features.html | 69 +++++ .../quartz-1.x/tutorial/more-about-jobs.html | 162 ++++++++++ .../tutorial/more-about-triggers.html | 151 ++++++++++ .../tutorial/scheduler-listeners.html | 87 ++++++ .../quartz-1.x/tutorial/simpletriggers.html | 121 ++++++++ .../tutorial/trigger-and-job-listeners.html | 96 ++++++ .../quartz-1.x/tutorial/using-quartz.html | 83 ++++++ .../quartz-2.x/configuration/index.html | 63 ++++ documentation/quartz-2.x/index.html | 55 ++++ documentation/quartz-2.x/migration-guide.html | 108 +++++++ documentation/quartz-2.x/quick-start.html | 208 +++++++++++++ .../advanced-enterprise-features.html | 70 +++++ ...-resource-usage-and-scheduler-factory.html | 94 ++++++ .../quartz-2.x/tutorial/crontrigger.html | 67 +++++ .../quartz-2.x/tutorial/crontriggers.html | 127 ++++++++ documentation/quartz-2.x/tutorial/index.html | 55 ++++ .../quartz-2.x/tutorial/job-stores.html | 108 +++++++ .../tutorial/jobs-and-triggers.html | 107 +++++++ .../tutorial/miscellaneous-features.html | 68 +++++ .../quartz-2.x/tutorial/more-about-jobs.html | 193 ++++++++++++ .../tutorial/more-about-triggers.html | 125 ++++++++ .../tutorial/scheduler-listeners.html | 88 ++++++ .../quartz-2.x/tutorial/simpletriggers.html | 126 ++++++++ .../tutorial/trigger-and-job-listeners.html | 98 ++++++ .../quartz-2.x/tutorial/using-quartz.html | 89 ++++++ .../quartz-3.x/configuration/reference.html | 186 ++++++++++++ documentation/quartz-3.x/index.html | 55 ++++ documentation/quartz-3.x/migration-guide.html | 95 ++++++ .../packages/aspnet-core-integration.html | 80 +++++ .../packages/hosted-services-integration.html | 99 +++++++ .../packages/json-serialization.html | 191 ++++++++++++ .../packages/microsoft-di-integration.html | 255 ++++++++++++++++ .../packages/opentelemetry-integration.html | 94 ++++++ .../packages/opentracing-integration.html | 77 +++++ .../quartz-3.x/packages/quartz-jobs.html | 71 +++++ .../quartz-3.x/packages/quartz-plugins.html | 71 +++++ .../timezoneconverter-integration.html | 74 +++++ documentation/quartz-3.x/quick-start.html | 280 ++++++++++++++++++ .../advanced-enterprise-features.html | 71 +++++ ...-resource-usage-and-scheduler-factory.html | 90 ++++++ .../quartz-3.x/tutorial/crontrigger.html | 84 ++++++ .../quartz-3.x/tutorial/crontriggers.html | 128 ++++++++ documentation/quartz-3.x/tutorial/index.html | 59 ++++ .../quartz-3.x/tutorial/job-stores.html | 114 +++++++ .../tutorial/jobs-and-triggers.html | 108 +++++++ .../tutorial/miscellaneous-features.html | 70 +++++ .../quartz-3.x/tutorial/more-about-jobs.html | 193 ++++++++++++ .../tutorial/more-about-triggers.html | 127 ++++++++ .../tutorial/scheduler-listeners.html | 89 ++++++ .../quartz-3.x/tutorial/simpletriggers.html | 128 ++++++++ .../tutorial/trigger-and-job-listeners.html | 99 +++++++ .../quartz-3.x/tutorial/using-quartz.html | 121 ++++++++ download.html | 56 ++++ faq.html | 31 ++ favicon-16x16.png | Bin 0 -> 1665 bytes favicon-32x32.png | Bin 0 -> 2721 bytes favicon-96x96.png | Bin 0 -> 11073 bytes favicon.ico | Bin 0 -> 1150 bytes features.html | 57 ++++ feed.atom | 177 +++++++++++ feed.json | 144 +++++++++ index.html | 61 ++++ license.html | 61 ++++ mailing-list.html | 56 ++++ mailing_list.html | 31 ++ manifest.json | 41 +++ migration_guide.html | 31 ++ ms-icon-144x144.png | Bin 0 -> 19676 bytes ms-icon-150x150.png | Bin 0 -> 20917 bytes ms-icon-310x310.png | Bin 0 -> 56934 bytes ms-icon-70x70.png | Bin 0 -> 7104 bytes quartz-logo-large.png | Bin 0 -> 32999 bytes quartz-logo-small.png | Bin 0 -> 13142 bytes rss.xml | 159 ++++++++++ sitemap.xml | 1 + tutorial/index.html | 31 ++ tutorial/lesson_1.html | 31 ++ tutorial/lesson_10.html | 31 ++ tutorial/lesson_11.html | 31 ++ tutorial/lesson_12.html | 31 ++ tutorial/lesson_2.html | 31 ++ tutorial/lesson_3.html | 31 ++ tutorial/lesson_4.html | 31 ++ tutorial/lesson_5.html | 31 ++ tutorial/lesson_6.html | 31 ++ tutorial/lesson_7.html | 31 ++ tutorial/lesson_8.html | 31 ++ tutorial/lesson_9.html | 31 ++ 320 files changed, 11280 insertions(+) create mode 100644 2012/04/09/quartznet-2-0-released/index.html create mode 100644 2012/04/22/quartznet-2-0-1-released/index.html create mode 100644 2012/12/31/quartznet-2-1-released/index.html create mode 100644 2013/01/05/quartznet-2-1-1-released/index.html create mode 100644 2013/01/13/quartznet-2-1-2-released/index.html create mode 100644 2013/10/09/quartznet-2-2-released/index.html create mode 100644 2013/11/24/quartznet-2-2-1-released/index.html create mode 100644 2014/01/06/website-moved-gihub-pages/index.html create mode 100644 2014/01/07/tutorial-updated-with-2-x-api-changes/index.html create mode 100644 2014/02/09/quartznet-2-2-2-released/index.html create mode 100644 2014/03/30/quartznet-2-2-3-released/index.html create mode 100644 2014/07/27/quartznet-2-2-4-released/index.html create mode 100644 2014/11/08/quartznet-2-3-released/index.html create mode 100644 2015/01/15/quartznet-2-3-1-released/index.html create mode 100644 2015/01/15/quartznet-2-3-2-released/index.html create mode 100644 2015/07/09/quartznet-2-3-3-released/index.html create mode 100644 2016/08/16/quartznet-3-0-alpha1-released/index.html create mode 100644 2016/08/18/quartznet-2-4-released/index.html create mode 100644 2016/08/24/quartznet-2-4-1-released/index.html create mode 100644 2016/08/24/quartznet-3-0-alpha2-released/index.html create mode 100644 2017/02/18/quartznet-2-5-released/index.html create mode 100644 2017/07/30/quartznet-2-6-released/index.html create mode 100644 2017/07/30/quartznet-3-0-alpha3-released/index.html create mode 100644 2017/10/08/quartznet-3-0-beta1-released/index.html create mode 100644 2017/10/09/quartznet-2-6-1-released/index.html create mode 100644 2017/12/30/quartznet-3-0-released/index.html create mode 100644 2018/01/21/quartznet-3-0-1-released/index.html create mode 100644 2018/01/25/quartznet-3-0-2-released/index.html create mode 100644 2018/02/24/quartznet-3-0-3-released/index.html create mode 100644 2018/03/04/quartznet-3-0-4-released/index.html create mode 100644 2018/05/27/quartznet-2-6-2-released/index.html create mode 100644 2018/05/27/quartznet-3-0-5-released/index.html create mode 100644 2018/07/06/quartznet-3-0-6-released/index.html create mode 100644 2018/10/07/quartznet-3-0-7-released/index.html create mode 100644 2020/07/06/website-refresh/index.html create mode 100644 2020/07/08/quartznet-3-1-beta-1-released/index.html create mode 100644 2020/07/14/quartznet-3-1-beta-2-released/index.html create mode 100644 2020/07/21/quartznet-3-1-beta-3-released/index.html create mode 100644 2020/07/21/quartznet-3-1-released/index.html create mode 100644 2020/07/24/quartznet-3-1-released/index.html create mode 100644 2020/10/01/quartznet-3-2-released/index.html create mode 100644 2020/10/18/quartznet-3-2-1-released/index.html create mode 100644 2020/10/19/quartznet-3-2-2-released/index.html create mode 100644 2020/10/31/quartznet-3-2-3-released/index.html create mode 100644 2021/01/19/quartznet-3-2-4-released/index.html create mode 100644 2021/04/07/quartznet-3-3-released/index.html create mode 100644 2021/04/08/quartznet-3-3-1-released/index.html create mode 100644 2021/04/09/quartznet-3-3-2-released/index.html create mode 100644 2021/08/01/quartznet-3-3-3-released/index.html create mode 100644 404.html create mode 100644 android-icon-144x144.png create mode 100644 android-icon-192x192.png create mode 100644 android-icon-36x36.png create mode 100644 android-icon-48x48.png create mode 100644 android-icon-72x72.png create mode 100644 android-icon-96x96.png create mode 100644 apple-icon-114x114.png create mode 100644 apple-icon-120x120.png create mode 100644 apple-icon-144x144.png create mode 100644 apple-icon-152x152.png create mode 100644 apple-icon-180x180.png create mode 100644 apple-icon-57x57.png create mode 100644 apple-icon-60x60.png create mode 100644 apple-icon-72x72.png create mode 100644 apple-icon-76x76.png create mode 100644 apple-icon-precomposed.png create mode 100644 apple-icon.png create mode 100644 assets/css/0.styles.af8ca635.css create mode 100644 assets/img/search.83621669.svg create mode 100644 assets/js/10.5459967e.js create mode 100644 assets/js/100.70eedb6c.js create mode 100644 assets/js/101.e7dd71b5.js create mode 100644 assets/js/102.d099ddb5.js create mode 100644 assets/js/103.4cce09e1.js create mode 100644 assets/js/104.8a143487.js create mode 100644 assets/js/105.bbb1e2b5.js create mode 100644 assets/js/106.8db45d2f.js create mode 100644 assets/js/107.7ec33075.js create mode 100644 assets/js/108.428f64db.js create mode 100644 assets/js/109.60b57a1e.js create mode 100644 assets/js/11.e2aadbde.js create mode 100644 assets/js/110.ee5b642d.js create mode 100644 assets/js/111.5ea56c24.js create mode 100644 assets/js/112.f9b9113a.js create mode 100644 assets/js/113.50eb57e0.js create mode 100644 assets/js/114.5a891d47.js create mode 100644 assets/js/115.503308f5.js create mode 100644 assets/js/116.edf242c3.js create mode 100644 assets/js/117.87d68a22.js create mode 100644 assets/js/118.1a20ec6b.js create mode 100644 assets/js/119.5545109a.js create mode 100644 assets/js/12.632699a6.js create mode 100644 assets/js/120.ac3b1282.js create mode 100644 assets/js/121.b9c8a72f.js create mode 100644 assets/js/122.702d9fad.js create mode 100644 assets/js/123.b873e59c.js create mode 100644 assets/js/124.73484c48.js create mode 100644 assets/js/125.1873365c.js create mode 100644 assets/js/126.2b8c172b.js create mode 100644 assets/js/127.ce06c938.js create mode 100644 assets/js/128.853bfa59.js create mode 100644 assets/js/129.a07b8371.js create mode 100644 assets/js/13.c53349db.js create mode 100644 assets/js/130.0feef69a.js create mode 100644 assets/js/131.c5fcddc7.js create mode 100644 assets/js/132.13fbd625.js create mode 100644 assets/js/133.f3d14f4d.js create mode 100644 assets/js/134.320abb38.js create mode 100644 assets/js/135.be16f19a.js create mode 100644 assets/js/136.de2948c9.js create mode 100644 assets/js/137.52cca593.js create mode 100644 assets/js/138.272768ba.js create mode 100644 assets/js/139.cb00fd64.js create mode 100644 assets/js/14.6535f905.js create mode 100644 assets/js/140.e168ce8e.js create mode 100644 assets/js/141.66280f26.js create mode 100644 assets/js/142.2f9f56f4.js create mode 100644 assets/js/143.35b86cf0.js create mode 100644 assets/js/144.419ebf8f.js create mode 100644 assets/js/145.4e24e5c4.js create mode 100644 assets/js/146.ec8464bd.js create mode 100644 assets/js/15.e0899e5a.js create mode 100644 assets/js/16.5066eada.js create mode 100644 assets/js/17.2cd0575f.js create mode 100644 assets/js/18.729d30ae.js create mode 100644 assets/js/19.e79f2201.js create mode 100644 assets/js/20.649245c0.js create mode 100644 assets/js/21.1a3614c5.js create mode 100644 assets/js/22.8a66bf8f.js create mode 100644 assets/js/23.e7ae5d25.js create mode 100644 assets/js/24.cde296f3.js create mode 100644 assets/js/25.346eb63b.js create mode 100644 assets/js/26.4a2442fe.js create mode 100644 assets/js/27.1ced7f91.js create mode 100644 assets/js/28.8cf196b8.js create mode 100644 assets/js/29.d3bbf14c.js create mode 100644 assets/js/3.836353be.js create mode 100644 assets/js/30.2285aa3b.js create mode 100644 assets/js/31.de5c4db1.js create mode 100644 assets/js/32.35d4940b.js create mode 100644 assets/js/33.32a324dc.js create mode 100644 assets/js/34.4cefe782.js create mode 100644 assets/js/35.3912f4fb.js create mode 100644 assets/js/36.3b387353.js create mode 100644 assets/js/37.193bf8a1.js create mode 100644 assets/js/38.83de4ad0.js create mode 100644 assets/js/39.9607a50c.js create mode 100644 assets/js/4.9a469852.js create mode 100644 assets/js/40.e5ff7906.js create mode 100644 assets/js/41.7affac67.js create mode 100644 assets/js/42.00fe8e23.js create mode 100644 assets/js/43.4f7d0962.js create mode 100644 assets/js/44.fd58bb75.js create mode 100644 assets/js/45.07c03278.js create mode 100644 assets/js/46.6b0f5704.js create mode 100644 assets/js/47.1b566e3b.js create mode 100644 assets/js/48.31882e6a.js create mode 100644 assets/js/49.350a7768.js create mode 100644 assets/js/5.b59b1de3.js create mode 100644 assets/js/50.511e3e44.js create mode 100644 assets/js/51.86078c87.js create mode 100644 assets/js/52.b04217a8.js create mode 100644 assets/js/53.d4849106.js create mode 100644 assets/js/54.568a20d9.js create mode 100644 assets/js/55.b96bcec3.js create mode 100644 assets/js/56.6c9b74df.js create mode 100644 assets/js/57.00f4144b.js create mode 100644 assets/js/58.816401b6.js create mode 100644 assets/js/59.39f29e19.js create mode 100644 assets/js/6.4b03a90b.js create mode 100644 assets/js/60.65653623.js create mode 100644 assets/js/61.7418f9a5.js create mode 100644 assets/js/62.0bc12fc5.js create mode 100644 assets/js/63.a9ad1d02.js create mode 100644 assets/js/64.d0324155.js create mode 100644 assets/js/65.4e9653df.js create mode 100644 assets/js/66.3e14e87f.js create mode 100644 assets/js/67.1aade945.js create mode 100644 assets/js/68.ada97766.js create mode 100644 assets/js/69.3918d066.js create mode 100644 assets/js/7.73b42248.js create mode 100644 assets/js/70.6d54ab0b.js create mode 100644 assets/js/71.a7334470.js create mode 100644 assets/js/72.337891b4.js create mode 100644 assets/js/73.6f58b4eb.js create mode 100644 assets/js/74.a79659d2.js create mode 100644 assets/js/75.ac772cc7.js create mode 100644 assets/js/76.ac780687.js create mode 100644 assets/js/77.b087b822.js create mode 100644 assets/js/78.0c35c107.js create mode 100644 assets/js/79.c0acd288.js create mode 100644 assets/js/8.d0570d6e.js create mode 100644 assets/js/80.f966b0e7.js create mode 100644 assets/js/81.a91e6c4f.js create mode 100644 assets/js/82.d6972444.js create mode 100644 assets/js/83.5fb1964c.js create mode 100644 assets/js/84.11a39734.js create mode 100644 assets/js/85.7a20170c.js create mode 100644 assets/js/86.f892a53a.js create mode 100644 assets/js/87.0a9e471c.js create mode 100644 assets/js/88.677da331.js create mode 100644 assets/js/89.52251cd3.js create mode 100644 assets/js/9.f3852c3d.js create mode 100644 assets/js/90.88b29d89.js create mode 100644 assets/js/91.4a66f8db.js create mode 100644 assets/js/92.46584aef.js create mode 100644 assets/js/93.e616473a.js create mode 100644 assets/js/94.8b47a217.js create mode 100644 assets/js/95.487cae6e.js create mode 100644 assets/js/96.848a034e.js create mode 100644 assets/js/97.d11e3968.js create mode 100644 assets/js/98.1252ce69.js create mode 100644 assets/js/99.f28f8a22.js create mode 100644 assets/js/app.78225083.js create mode 100644 assets/js/vendors~docsearch.eec9cc92.js create mode 100644 blog create mode 100644 blog.html create mode 100644 blogpage/2/index.html create mode 100644 blogpage/3/index.html create mode 100644 blogpage/4/index.html create mode 100644 blogpage/5/index.html create mode 100644 browserconfig.xml create mode 100644 documentation/best-practices.html create mode 100644 documentation/faq.html create mode 100644 documentation/index.html create mode 100644 documentation/quartz-1.x/index.html create mode 100644 documentation/quartz-1.x/tutorial/advanced-enterprise-features.html create mode 100644 documentation/quartz-1.x/tutorial/configuration-resource-usage-and-scheduler-factory.html create mode 100644 documentation/quartz-1.x/tutorial/crontriggers.html create mode 100644 documentation/quartz-1.x/tutorial/index.html create mode 100644 documentation/quartz-1.x/tutorial/job-stores.html create mode 100644 documentation/quartz-1.x/tutorial/jobs-and-triggers.html create mode 100644 documentation/quartz-1.x/tutorial/miscellaneous-features.html create mode 100644 documentation/quartz-1.x/tutorial/more-about-jobs.html create mode 100644 documentation/quartz-1.x/tutorial/more-about-triggers.html create mode 100644 documentation/quartz-1.x/tutorial/scheduler-listeners.html create mode 100644 documentation/quartz-1.x/tutorial/simpletriggers.html create mode 100644 documentation/quartz-1.x/tutorial/trigger-and-job-listeners.html create mode 100644 documentation/quartz-1.x/tutorial/using-quartz.html create mode 100644 documentation/quartz-2.x/configuration/index.html create mode 100644 documentation/quartz-2.x/index.html create mode 100644 documentation/quartz-2.x/migration-guide.html create mode 100644 documentation/quartz-2.x/quick-start.html create mode 100644 documentation/quartz-2.x/tutorial/advanced-enterprise-features.html create mode 100644 documentation/quartz-2.x/tutorial/configuration-resource-usage-and-scheduler-factory.html create mode 100644 documentation/quartz-2.x/tutorial/crontrigger.html create mode 100644 documentation/quartz-2.x/tutorial/crontriggers.html create mode 100644 documentation/quartz-2.x/tutorial/index.html create mode 100644 documentation/quartz-2.x/tutorial/job-stores.html create mode 100644 documentation/quartz-2.x/tutorial/jobs-and-triggers.html create mode 100644 documentation/quartz-2.x/tutorial/miscellaneous-features.html create mode 100644 documentation/quartz-2.x/tutorial/more-about-jobs.html create mode 100644 documentation/quartz-2.x/tutorial/more-about-triggers.html create mode 100644 documentation/quartz-2.x/tutorial/scheduler-listeners.html create mode 100644 documentation/quartz-2.x/tutorial/simpletriggers.html create mode 100644 documentation/quartz-2.x/tutorial/trigger-and-job-listeners.html create mode 100644 documentation/quartz-2.x/tutorial/using-quartz.html create mode 100644 documentation/quartz-3.x/configuration/reference.html create mode 100644 documentation/quartz-3.x/index.html create mode 100644 documentation/quartz-3.x/migration-guide.html create mode 100644 documentation/quartz-3.x/packages/aspnet-core-integration.html create mode 100644 documentation/quartz-3.x/packages/hosted-services-integration.html create mode 100644 documentation/quartz-3.x/packages/json-serialization.html create mode 100644 documentation/quartz-3.x/packages/microsoft-di-integration.html create mode 100644 documentation/quartz-3.x/packages/opentelemetry-integration.html create mode 100644 documentation/quartz-3.x/packages/opentracing-integration.html create mode 100644 documentation/quartz-3.x/packages/quartz-jobs.html create mode 100644 documentation/quartz-3.x/packages/quartz-plugins.html create mode 100644 documentation/quartz-3.x/packages/timezoneconverter-integration.html create mode 100644 documentation/quartz-3.x/quick-start.html create mode 100644 documentation/quartz-3.x/tutorial/advanced-enterprise-features.html create mode 100644 documentation/quartz-3.x/tutorial/configuration-resource-usage-and-scheduler-factory.html create mode 100644 documentation/quartz-3.x/tutorial/crontrigger.html create mode 100644 documentation/quartz-3.x/tutorial/crontriggers.html create mode 100644 documentation/quartz-3.x/tutorial/index.html create mode 100644 documentation/quartz-3.x/tutorial/job-stores.html create mode 100644 documentation/quartz-3.x/tutorial/jobs-and-triggers.html create mode 100644 documentation/quartz-3.x/tutorial/miscellaneous-features.html create mode 100644 documentation/quartz-3.x/tutorial/more-about-jobs.html create mode 100644 documentation/quartz-3.x/tutorial/more-about-triggers.html create mode 100644 documentation/quartz-3.x/tutorial/scheduler-listeners.html create mode 100644 documentation/quartz-3.x/tutorial/simpletriggers.html create mode 100644 documentation/quartz-3.x/tutorial/trigger-and-job-listeners.html create mode 100644 documentation/quartz-3.x/tutorial/using-quartz.html create mode 100644 download.html create mode 100644 faq.html create mode 100644 favicon-16x16.png create mode 100644 favicon-32x32.png create mode 100644 favicon-96x96.png create mode 100644 favicon.ico create mode 100644 features.html create mode 100644 feed.atom create mode 100644 feed.json create mode 100644 index.html create mode 100644 license.html create mode 100644 mailing-list.html create mode 100644 mailing_list.html create mode 100644 manifest.json create mode 100644 migration_guide.html create mode 100644 ms-icon-144x144.png create mode 100644 ms-icon-150x150.png create mode 100644 ms-icon-310x310.png create mode 100644 ms-icon-70x70.png create mode 100644 quartz-logo-large.png create mode 100644 quartz-logo-small.png create mode 100644 rss.xml create mode 100644 sitemap.xml create mode 100644 tutorial/index.html create mode 100644 tutorial/lesson_1.html create mode 100644 tutorial/lesson_10.html create mode 100644 tutorial/lesson_11.html create mode 100644 tutorial/lesson_12.html create mode 100644 tutorial/lesson_2.html create mode 100644 tutorial/lesson_3.html create mode 100644 tutorial/lesson_4.html create mode 100644 tutorial/lesson_5.html create mode 100644 tutorial/lesson_6.html create mode 100644 tutorial/lesson_7.html create mode 100644 tutorial/lesson_8.html create mode 100644 tutorial/lesson_9.html diff --git a/2012/04/09/quartznet-2-0-released/index.html b/2012/04/09/quartznet-2-0-released/index.html new file mode 100644 index 000000000..46c6ce454 --- /dev/null +++ b/2012/04/09/quartznet-2-0-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 2.0 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.NET 2.0 has finally been released. Quartz.NET 2.0 introduces a new more interfaced based model of operating with the API, lots of performance improvements and bug fixes to issues found in 1.0.x line.

BREAKING CHANGES

  • .NET 1.1 and 2.0 support is dropped
  • Quartz.NET now needs .NET version 3.5 SP1 or later to run due to use of new language features and classes
  • Many public interface methods have changed from returning arrays to generic IList or ISet interfaces
  • TriggerBuilder implementations and JobBuilder should now be used to create different job and trigger definitions
  • Introduced IJobDetail, IContrigger, ISimpleTrigger, ICalendarIntervalTrigger have far less members and especially mutators
  • When C5 collections were introduced as set-based implementation provider, ISet and ISortedSet interfaces were narrowed (IList inheritance removed)
  • string triggerName, string triggerGroup are now encapsulated in TriggerKey (has the same fields)
  • string jobName, string jobGroup are now encapsulated in JobKey (has the same fields)
  • JobInitializationPlugin is now deprecated in favor of XMLSchedulingDataProcessorPlugin, JobInitializationPlugin no longer included
  • Microsoft's Oracle drivers are no longer supported, use 10g or 11g ODP.NET drivers
  • Database schema has changed, you need to convert your 1.x schema to new version, sample migration script available in database folder

OTHER NOTABLE CHANGES

  • XMLSchedulingDataProcessorPlugin uses new XML format that allows more control over triggers but no support for calendars
  • There are extension methods for the new trigger builder that allow you to set trigger specifics
  • Client Profile is now supported and there are now separate DLLs for client profile
  • PropertySettingJobFactory is now the default JobFactory

Please see the change log (opens new window) for complete list of changes.

Quartz.NET is also available as NuGet package. You can install it with command:

Install-Package Quartz
+

This version corresponds to Java Quartz's version 2.1.

Big thanks to Quartz.NET community that has sumbitted pull requests, patches, bug reports and for being so active and making the 2.0 release possible!

There's a first version of migration guide but the tutorial hasn't been updated yet. You can also always check Java Quartz's documentation (opens new window).

+ + + diff --git a/2012/04/22/quartznet-2-0-1-released/index.html b/2012/04/22/quartznet-2-0-1-released/index.html new file mode 100644 index 000000000..796581ea2 --- /dev/null +++ b/2012/04/22/quartznet-2-0-1-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.0.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a maintenance release containing a critical fix to Oracle job store support.

FIXES

  • Oracle database support broken
  • Incorrect .NET 4.5 requirement in 4.0 build (only NuGet affected)
  • XML validation fails as schema not embedded (only NuGet affected)
  • ObjectUtils.SetPropertyValue fails with explicitly implemented interface members
+ + + diff --git a/2012/12/31/quartznet-2-1-released/index.html b/2012/12/31/quartznet-2-1-released/index.html new file mode 100644 index 000000000..9f78edb06 --- /dev/null +++ b/2012/12/31/quartznet-2-1-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 2.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

To welcome year 2013 we are releasing new and improved version of Quart.NET! +This release contains important bug fixes, new functionality and minor breaking changes.

  • C5 depedency is now internalized and allows you to use whatever version you want outside of Quartz.
  • Custom IJobFactory implementations now need to implement new method void ReturnJob(IJob job) for container managed cleanup.
  • NthIncludedDayTrigger was removed as it was accidentally left behind even though being legacy and replaced by DailyTimeIntervalTrigger.

NEW FEATURES

  • TimeZone support for calendars / Andrew Smith
  • Allow scheduling relative to replaced trigger with XML configuration
  • Add method to IJobFactory to destroy a job instance created by the factory breaking / minor breaking, added new required method
  • Internalize C5 dependency
  • Support for Oracle ODP 11.2 Release 4
  • Upgrade SQLite dependency to version 1.0.83
  • Upgrade to Common.Logging 2.1.2

FIXES

  • Scheduled Shutdown blocked even if waitForJobsToComplete is false
  • DailyTimeIntervalTriggerImpl should be serializable
  • InstanceID = "AUTO" may cause "String or binary data would be truncated" error on qrtz_fired_triggers.entry_id
  • PlugInExample doesn't execute any jobs
  • Recovering triggers have empty/incorrect JobDataMap
  • Make Quartz.NET work under medium trust when running .NET 3.5
  • tables_oracle.sql uses deprecated VARCHAR type
  • Improve error reporting for database connection failure
  • Scheduler Shutdown Freezes when There are Jobs Still Running
  • Use System.Version instead of FileVersionInfo to retive current Quartz version
  • DailyTimeIntervalTriggerImpl Validate broken

BREAKING CHANGES

  • Remove NthIncludedDayTrigger that was supposed to be removed in 2.0
  • Remove Visual Studio 2008 solutions and projects
  • Add support for DateTimeOffset and TimeSpan to JobDataMap / minor breaking - cleanup of API

Special thanks to Andrew Smith for working hard on TimeZone support. Credits go also to our vibrant community actively helping on mailing list and reporting issues and creating pull requests.

+ + + diff --git a/2013/01/05/quartznet-2-1-1-released/index.html b/2013/01/05/quartznet-2-1-1-released/index.html new file mode 100644 index 000000000..913220b55 --- /dev/null +++ b/2013/01/05/quartznet-2-1-1-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.1.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2013/01/13/quartznet-2-1-2-released/index.html b/2013/01/13/quartznet-2-1-2-released/index.html new file mode 100644 index 000000000..59d5af10e --- /dev/null +++ b/2013/01/13/quartznet-2-1-2-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.1.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2013/10/09/quartznet-2-2-released/index.html b/2013/10/09/quartznet-2-2-released/index.html new file mode 100644 index 000000000..218a347ff --- /dev/null +++ b/2013/10/09/quartznet-2-2-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 2.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release contains important bug fixes, new functionality and minor breaking changes.

UPGRADING

Please examine and run the database\schema_20_to_22_upgrade.sql script if you are using AdoJobStore +this script adds a new column SCHED_TIME to table QRTZ_FIRED_TRIGGERS +file contains the alter command for SQL Server and other database samples in comments

BREAKING CHANGES

  • database schema needs upgrade
  • add SchedulerStarting() method to ISchedulerListener interface
  • make the scheduler's TypeLoadHelper available to plugins when they are initialized
  • dbFailureRetryInterval parameter was removed from DirectSchedulerFactory APIs

NEW FEATURES

  • ability to override worker thread names (when using SimpleThreadPool)
  • add new IScheduler method: ScheduleJob(IJobDetail job, ISet trigger) to schedule multiple triggers for a job all at once
  • allow 'triggerless' initial storing of non-durable jobs.
  • improvements for job recovery information
  • package job_scheduling_data_2_0.xsd to nuget package's content folder
  • allow scheduler exported with remoting to be used from local machine only
  • support for Oracle managed ODP driver

FIXES

  • job ending with exception and trigger not going to fire again, trigger is incorrectly not removed from job store
  • XML schema supports multiple schedule elements but processor does not
  • DailyTimeIntervalTriggerPersistenceDelegate does not handle empty time interval properly
  • DailyTimeIntervalScheduleBuilder.EndingDailyAfterCount(...) doesn't pass validation
  • trace throwing exception
  • bug in QuartzSchedulerThread.GetRandomizedIdleWaitTime()
  • can't delete or replace job without the referenced class

MISC

  • Performance improvements, including improvements to some select statements in AdoJobStore
+ + + diff --git a/2013/11/24/quartznet-2-2-1-released/index.html b/2013/11/24/quartznet-2-2-1-released/index.html new file mode 100644 index 000000000..eff7edf8b --- /dev/null +++ b/2013/11/24/quartznet-2-2-1-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.2.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a minor release containing mostly bug fixes.

NEW FEATURES

  • GroupMatcher.AnyGroup() support
  • Add network credential and SMTP port definition support to SendMailJob

FIXES

  • SchedulerException constructor unnecessarily uses Exception.ToString as message
  • Thread name prefix for thread pool is not set
  • Triggers should not be excluded based on the fire time of the first selected trigger
  • Quarts server does not properly log possible exception when starting the service
  • DailyTimeIntervalTrigger GetFireTimeAfter produces incorrect result when date is in the past
  • batchTriggerAcquisitionMaxCount acquires one trigger unless batchTriggerAcquisitionFireAheadTimeWindow is also set
  • Oracle ODP Managed provider should set BindByName to true for OracleCommands
+ + + diff --git a/2014/01/06/website-moved-gihub-pages/index.html b/2014/01/06/website-moved-gihub-pages/index.html new file mode 100644 index 000000000..44a9fad08 --- /dev/null +++ b/2014/01/06/website-moved-gihub-pages/index.html @@ -0,0 +1,55 @@ + + + + + + Website has moved to using GitHub pages | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2014/01/07/tutorial-updated-with-2-x-api-changes/index.html b/2014/01/07/tutorial-updated-with-2-x-api-changes/index.html new file mode 100644 index 000000000..3122e1b3a --- /dev/null +++ b/2014/01/07/tutorial-updated-with-2-x-api-changes/index.html @@ -0,0 +1,56 @@ + + + + + + The tutorial has been updated to include 2.x API changes | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2014/02/09/quartznet-2-2-2-released/index.html b/2014/02/09/quartznet-2-2-2-released/index.html new file mode 100644 index 000000000..e971205f1 --- /dev/null +++ b/2014/02/09/quartznet-2-2-2-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 2.2.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a minor release fixing couple of minor bugs.

FIXES

  • long properties incorrectly read as int in SimplePropertiesTriggerPersistenceDelegateSupport
  • RecoveringTriggerKey in JobExecutionContext has group and name wrong way around
  • Make SQL Server table create script Azure SQL compliant
  • Add missing clustered index for QRTZ_BLOB_TRIGGERS table +** You need to manually add this to existing installation (tables created with old script), see ALTER TABLE [dbo].QRTZ_BLOB_TRIGGERS WITH NOCHECK ADD... in script
+ + + diff --git a/2014/03/30/quartznet-2-2-3-released/index.html b/2014/03/30/quartznet-2-2-3-released/index.html new file mode 100644 index 000000000..cdace0899 --- /dev/null +++ b/2014/03/30/quartznet-2-2-3-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 2.2.3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a bug fix release which has some critical fixes, especially for CalendarIntevalTrigger +future date calculation and trigger's next fires not being processed in a timely fashion when AdoJobStore is used +with DisallowConcurrentExecutionAttribute and trigger has short repeat interval.

This update is highly recommended for all users.

FIXES

  • StdAdoConstants.SqlSelectSchedulerStates does not filter on the SCHED_NAME column
  • CalendarIntervalTrigger produces incorrect schedule
  • Trigger completion signaling from AdoJobStore does not work properly when DisallowConcurrentExecution is set

NEW FEATURES

  • IDisposable jobs should be disposed after execution
  • Support for defining DbMetadata via App.config's quartz section
+ + + diff --git a/2014/07/27/quartznet-2-2-4-released/index.html b/2014/07/27/quartznet-2-2-4-released/index.html new file mode 100644 index 000000000..218538577 --- /dev/null +++ b/2014/07/27/quartznet-2-2-4-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.2.4 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a bug fix release addressing some minor issues.

FIXES

  • Cannot register trigger persistence delegates with assembly qualified names
  • Set example server's current directory to the one where server.exe is
  • Fix TimeZoneInfo.GetUtcOffset(DateTimeOffset dateTimeOffset) not implemented in Mono
  • Gracefully handle mixed useProperties usage when reading from DB when useproperties value has changed
  • FindSystemTimeZoneById should work with both 'Coordinated Universal Time' and 'UTC'
  • Latest release (2.2.3) didn't include Dbprovider constant string in StdSchedulerFactory - running examples fails
+ + + diff --git a/2014/11/08/quartznet-2-3-released/index.html b/2014/11/08/quartznet-2-3-released/index.html new file mode 100644 index 000000000..892fbd094 --- /dev/null +++ b/2014/11/08/quartznet-2-3-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a bug fix release with some changes that warrant a minor version increment.

NEW FEATURE

  • Upgrade to Common.Logging 2.3.1
  • Add ability to check if calendar exists in job store
  • Add FirebirdDelegate and update Firebird driver

FIXES

  • DailyTimeIntervalTriggerImpl fires twice during daylight saving time day
  • No wait time between db connection failures with AcquireNextTriggers causes excessive logging
  • Configure the quartz server in the <quartz> section fails
  • CronExpression ctor incorrectly uses the non-uppercased string
  • Triggers fired milliseconds too early
  • Loading of Quartz 4.0 DLL fails on systems with no .NET 4.5 installed
+ + + diff --git a/2015/01/15/quartznet-2-3-1-released/index.html b/2015/01/15/quartznet-2-3-1-released/index.html new file mode 100644 index 000000000..ecc39bb7e --- /dev/null +++ b/2015/01/15/quartznet-2-3-1-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 2.3.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a bug fix release with upgraded Common.Logging dependency, also problems running +under .NET 4.0 should now be finally fixed.

NEW FEATURE

  • Upgrade to Common.Logging 3.0.0

FIXES

  • JobDetailImpl members should be virtual
  • Triggers do not transition to error state in AdoJobStore when job retrieval fails during trigger acquisition
  • Quartz.Server.exe.config refers to wrong Common.Logging.Log4Net assembly
  • Incorrect NextFireTime when 'schedule-trigger-relative-to-replaced-trigger' = 'true'
  • Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' from assembly mscorlib
  • TriggerBuilder.UsingJobData(JobDataMap newJobDataMap) should ovewrite existing data
+ + + diff --git a/2015/01/15/quartznet-2-3-2-released/index.html b/2015/01/15/quartznet-2-3-2-released/index.html new file mode 100644 index 000000000..ced199727 --- /dev/null +++ b/2015/01/15/quartznet-2-3-2-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.3.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a minor release containing mostly bug fixes.

NEW FEATURE

  • Add mysql 6.9.5 provider support

FIXES

  • Avoid unnecessary object allocations in CronExpression
  • CalendarIntervalTrigger and DailyTimeIntervalTrigger produce incorrect schedule builders
  • Incorrect multiplication factor in DailyTimeIntervalScheduleBuilder.EndingDailyAfterCount()
  • AnnualCalendar SetDayExcluded does not update internal data structures if base calendar excludes date
  • Ensure IDriverDelegate members in StdAdoDelegate are virtual
  • Several XML documentation spelling error fixes
+ + + diff --git a/2015/07/09/quartznet-2-3-3-released/index.html b/2015/07/09/quartznet-2-3-3-released/index.html new file mode 100644 index 000000000..dac8c18eb --- /dev/null +++ b/2015/07/09/quartznet-2-3-3-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.3.3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a minor release containing mostly bug fixes.

NEW FEATURE

  • Support generic job types with AdoJobStore

FIXES

  • AdoJobStore doesn't notify about removing orphaned job
  • Store null JobData in JobDetails if it's empty
  • Documentation error in SimpleTriggerImpl UpdateAfterMisfire
  • Ensure IDriverDelegate members in StdAdoDelegate are virtual
+ + + diff --git a/2016/08/16/quartznet-3-0-alpha1-released/index.html b/2016/08/16/quartznet-3-0-alpha1-released/index.html new file mode 100644 index 000000000..62eea36e4 --- /dev/null +++ b/2016/08/16/quartznet-3-0-alpha1-released/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET 3.0 Alpha 1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is the first alpha release from the long-awaited v3 branch. This is a big overhaul (and still in progress). Internals are being modernized whilst still trying to keep sane upgrade path.

A big thank you goes to Mike Rousos (opens new window) who really made it possible to get Quartz.NET working on .NET Core. Daniel Marbach (opens new window) also contributed a lot with ideas and code to async side. And of course never forgetting the community members that have provided feedback and fixes.

Please see the migration guide that is a work in progess.

Use at your own risk, might not be that production ready yet

What does alpha mean?

  • All existing (and new) tests passing
  • Cheese might still get moved, alpha means that APIs can change, features can come and go

NEW FEATURE

  • Task based jobs with async/await support, internals work in async/await manner
  • Support .NET Core / netstandard 1.3
  • Separate NuGet package Quartz.Serialization.Json to enable JSON based AdoJobStore serialization (no binary serialization available in .NET Core)
  • Common.Logging removed from dependencies
  • C5 Collections removed from ILMerge process, no longer needed

BREAKING CHANGES

  • .NET 4.5/netstandard1.3 required
  • SimpleThreadPool is gone, old owned threads are gone
  • Scheduler methods have been changed to be Task based, remember to await them
  • IJob interface now returns a task
  • Some IList properties have been changed to IReadOnlyList to properly reflect intent
  • SQL Server CE support has been dropped
  • DailyCalendar uses now datetimes for excluded dates and has ISet interface to access them
  • IObjectSerializer has new method, void Initialize(), that has to be implemented
  • IInterruptableJob removed in favor of context's CancellationToken

KNOWN ISSUES

  • Issues with time zone ids between Windows and Linux, they use different ids for the same zone
  • No remoting support
  • Documentation lacking

Check NuGet for pre-release packages.

+ + + diff --git a/2016/08/18/quartznet-2-4-released/index.html b/2016/08/18/quartznet-2-4-released/index.html new file mode 100644 index 000000000..95ec0c9e0 --- /dev/null +++ b/2016/08/18/quartznet-2-4-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 2.4 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Right on the heels of [Quartz.NET 3.0 Alpha 1]({% post_url 2016-08-16-quartznet-3.0-alpha1-released %}) we now have +a small maintenance version. With version 2.4 we are slowing things down with 2.x series and concentrate effors on v3 development.

NEW FEATURE

  • Add SQL limit support for MySQLDelegate
  • Removed dbFailureRetryInterval since it is no longer used
  • Update Common Logging to v3.3.1

FIXES

  • Batch acquisition can cause early firing of triggers
  • Should not rely on C5.TreeSet<T> on HolidayCalendar field serialization
+ + + diff --git a/2016/08/24/quartznet-2-4-1-released/index.html b/2016/08/24/quartznet-2-4-1-released/index.html new file mode 100644 index 000000000..774662eae --- /dev/null +++ b/2016/08/24/quartznet-2-4-1-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 2.4.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2016/08/24/quartznet-3-0-alpha2-released/index.html b/2016/08/24/quartznet-3-0-alpha2-released/index.html new file mode 100644 index 000000000..a5c8f94ea --- /dev/null +++ b/2016/08/24/quartznet-3-0-alpha2-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.0 Alpha 2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is the second alpha of v3. This release fixes problems with schedule signaling when AdoJobStore is in use. +This release removes the last bits of Quartz's usage of thread local storage and thus makes async-based operations a lot safer.

FIXES

  • fix scheduler signaling not working with AdoJobStore due to thread local storage
  • thread local state removed altogether
  • quartz.serializer.type was required even though non-serializing RAMJobStore was in use
  • JSON serialization incorrectly called serialization callbacks

BREAKING CHANGES

  • IStatefulJob was removed, been obsolete since 2.x
  • ISemaphore interface now passes Guid requestorId that defines lock owner instead of implicit thread name

KNOWN ISSUES

  • Issues with time zone ids between Windows and Linux, they use different ids for the same zone
  • No remoting support
  • Documentation lacking

Check NuGet for pre-release packages.

+ + + diff --git a/2017/02/18/quartznet-2-5-released/index.html b/2017/02/18/quartznet-2-5-released/index.html new file mode 100644 index 000000000..5d0f6ada6 --- /dev/null +++ b/2017/02/18/quartznet-2-5-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 2.5 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release contains mainly bug fixes but because there's a behavioral change in +DST handling (for the better) that warrants for a minor version number increment.

See the GitHub issue (opens new window) for details.

FIXES

  • Jobs get stuck in the Blocked state after the DB connection is lost in NotifyJobListenersComplete (#282)
  • Oracle rownum based queries can work wrong after Oracle SQL tuning task has ran (#413)
  • Handle DST better (#317)
  • RAMJobStore fails to resume when paused without triggers (#433)
  • CronExpression doesn't properly check the range when an "/interval" is specified (#432)
  • Fix JobDataMap dirty flag when constructing from existing map (#431)
  • Store triggers by job in RAMJobStore for better performance (#430)
  • Create WorkerThread in virtual method (#426)
  • SqlSelectJobForTrigger is not using primary key join and causes index scan (#407)
+ + + diff --git a/2017/07/30/quartznet-2-6-released/index.html b/2017/07/30/quartznet-2-6-released/index.html new file mode 100644 index 000000000..2419d527a --- /dev/null +++ b/2017/07/30/quartznet-2-6-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.6 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Addition of column required to database

  • This release fixes a long standing issue, DailyTimeIntervalTrigger's time zone is now finally persisted to database
  • This requires running schema_25_to_26_upgrade.sql (opens new window) to add new column to QRTZ_SIMPROP_TRIGGERS table

A slight performance boost can also be unlocked when using PostgreSQL by switching PostgreSqlDelegate.

NEW FEATURE

  • Add support for eager validation of job scheduling XML file on plugin start (#492)
  • Add support for extra custom time zone resolver function in TimeZoneUtil (#290)

FIXES

  • CalendarIntervalTrigger's first fire time doesn't consider time zone (#505)
  • QRTZ_FIRED_TRIGGERS.ENTRY_ID column length too small (#474)
  • Decrease log level for message when host name is too long (#471)
  • Quartz should not log transient faults related to azure db connection as errors (#470)
  • RemotingSchedulerExporter can't create remoting channel on Mono (#464)
  • Regression in 2.5, TriggerBuilder.UsingJobData(JobDataMap newJobDataMap) should ovewrite existing (#460)
  • QuartzScheduler.Clear does not clear QRTZ_FIRED_TRIGGERS table (#437)
  • No wait time between db connection failures with AcquireNextTriggers (#428)
  • DailyTimeIntervalTriggerImpl prevents altering EndTimeOfDay to a later time of day (#382)
  • Quartz.CronExpression.IsSatisfiedBy claims to ignore milliseconds but doesn't (#349)
  • Add back PostgreSqlDelegate to support database LIMIT in trigger acquiring (#318)
  • Bug in XSD schema: cannot set IgnoreMisfirePolicy (#280)
  • Quartz.Xml.XMLSchedulingDataProcessor uses GetType() instead of typeof(Quartz.Xml.XMLSchedulingDataProcessor) (#277)
  • With SQLite default isolation level should be set to serializable (#242)
  • DailyTimeIntervalTrigger's time zone is not persisted into database (#136)
  • XMLSchedulingDataProcessorPlugin incompatible with StdAdoDelegate when useProperties=true (#44)
  • Trigger loop encountered using DailyTimeIntervalTrigger across DST start boundary (#332)
+ + + diff --git a/2017/07/30/quartznet-3-0-alpha3-released/index.html b/2017/07/30/quartznet-3-0-alpha3-released/index.html new file mode 100644 index 000000000..a8684b355 --- /dev/null +++ b/2017/07/30/quartznet-3-0-alpha3-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 3.0 Alpha 3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is the third alpha of v3. APIs have had some love in form of adding CancellationToken support and +using more IReadOnlyCollection<T>s more concisely. Unfortunately we still don't have the story done for +remote management support (HTTP API).

When using AdoJobStore: make sure to run both 2.6 and 3.0 SQL migration scripts if you are upgrading from 2.5, otherwise just 3.0 migration script

NEW FEATURE

  • support for .NET Standard 2.0 preview (#486)
  • support for MySQL on .NET Standard via provider 'MySql' (#493)
  • change SQL database IMAGE types to VARBINARY - requires migration schema_26_to_30.sql
  • add ISchedulerListener.JobInterrupted(JobKey jobKey, CancellationToken cancellationToken) (#467)

FIXES

  • fix PosgreSQL db provider configuration for .NET Core (#449)
  • CancellationToken is now supported in async methods (#444)
  • fix regression with XML schema validation

BREAKING CHANGES

  • possibly breaking, cron expression validation is now stricter (#315 #485)
  • .NET 4.6 required instead of old 4.5
  • API methods have been revisited to mainly use IReadOnlyCollection<T>, this hides both HashSet<T>s and List<T>s
  • LibLog has been hidden as internal (ILog etc), like it was originally intended to be

KNOWN ISSUES

  • Issues with time zone ids between Windows and Linux, they use different ids for the same zone
  • No remoting support
  • Documentation lacking

Check NuGet for pre-release packages.

+ + + diff --git a/2017/10/08/quartznet-3-0-beta1-released/index.html b/2017/10/08/quartznet-3-0-beta1-released/index.html new file mode 100644 index 000000000..0c0cc1c45 --- /dev/null +++ b/2017/10/08/quartznet-3-0-beta1-released/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET 3.0 Beta 1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is the first beta of v3. Stabilization and testing has been well underway.

When using AdoJobStore: make sure to run both 2.6 and 3.0 SQL migration scripts if you are upgrading from 2.5, otherwise just 3.0 migration script

NEW FEATURE

  • returned .NET Framework 4.5.2 compatibility to better support library consumers like NServiceBus and MassTransit
  • netstandard 2.0 is now minimum for .NET Core
  • support for Microsoft.Data.Sqlite via provider name SQLite-Microsoft, the old provider SQLite also still works
  • Firebird is supported in .NET Core
  • Added preliminary support for SQL Server Memory-Optimized tables and Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT

BREAKING CHANGES

  • Jobs and plugins are now in a separate assemblies/NuGet packages Quartz.Jobs and Quartz.Plugins
  • ADO.NET provider names have been simplified, the provider names are without version, e.g. SqlServer-20 => SqlServer

KNOWN ISSUES

  • Issues with time zone ids between Windows and Linux, they use different ids for the same zone
  • No remoting support for .NET Core
  • Documentation lacking

Check NuGet for pre-release packages.

+ + + diff --git a/2017/10/09/quartznet-2-6-1-released/index.html b/2017/10/09/quartznet-2-6-1-released/index.html new file mode 100644 index 000000000..db6c2a776 --- /dev/null +++ b/2017/10/09/quartznet-2-6-1-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.6.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a maintenance release fixing an issue where misfire handling is being too slow at times. This regression has been present since version 2.4.

NEW FEATURE

  • Allow performing misfire handling more frequently than misfireThreshold (#532)

FIXES

  • Incomplete recovery of misfired jobs when using database-specific delegate types (#531)
+ + + diff --git a/2017/12/30/quartznet-3-0-released/index.html b/2017/12/30/quartznet-3-0-released/index.html new file mode 100644 index 000000000..a10c5932a --- /dev/null +++ b/2017/12/30/quartznet-3-0-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 3.0 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

The wait is over, Quartz.NET 3.0 is here with .NET Core support and async/await!

A big thank you goes to Mike Rousos (opens new window) who really made it possible to get Quartz.NET working on .NET Core. +Daniel Marbach (opens new window) also contributed a lot with ideas and code to async side. +And of course never forgetting the community members that have provided feedback and fixes.

Please see the migration guide.

NEW FEATURE

  • Task based jobs with async/await support, internals work in async/await manner
  • Support .NET Core / netstandard 2.0 and .NET Framework 4.5.2 and later
  • Support for Microsoft.Data.Sqlite via provider name SQLite-Microsoft, the old provider SQLite also still works
  • Added preliminary support for SQL Server Memory-Optimized tables and Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT
  • Common.Logging removed from dependencies
  • C5 Collections removed from ILMerge process, no longer needed
  • Add support for eager validation of job scheduling XML file on plugin start
  • Add support for extra custom time zone resolver function in TimeZoneUtil

BREAKING CHANGES

  • Jobs and plugins are now in a separate assemblies/NuGet packages Quartz.Jobs and Quartz.Plugins
  • ADO.NET provider names have been simplified, the provider names are without version, e.g. SqlServer-20 => SqlServer
  • API methods have been revisited to mainly use IReadOnlyCollection<T>, this hides both HashSet<T>s and List<T>s
  • LibLog has been hidden as internal (ILog etc), like it was originally intended to be
  • SimpleThreadPool is gone, old owned threads are gone
  • Scheduler methods have been changed to be Task based, remember to await them
  • IJob interface now returns a task
  • Some IList properties have been changed to IReadOnlyList to properly reflect intent
  • SQL Server CE support has been dropped
  • DailyCalendar uses now datetimes for excluded dates and has ISet interface to access them
  • IObjectSerializer has new method, void Initialize(), that has to be implemented
  • IInterruptableJob removed in favor of context's CancellationToken

KNOWN ISSUES

  • Issues with time zone ids between Windows and Linux, they use different ids for the same zone
  • No remoting support for .NET Core
+ + + diff --git a/2018/01/21/quartznet-3-0-1-released/index.html b/2018/01/21/quartznet-3-0-1-released/index.html new file mode 100644 index 000000000..70d56054d --- /dev/null +++ b/2018/01/21/quartznet-3-0-1-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 3.0.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a bug fix release that fixes cron expression parsing bug and reverts IRemotableQuartzScheduler +interface back to its original form without Tasks and CancellationTokens - so that's it's actually usable +through .NET Remoting infrastructure. Now zip packing is also back and includes Quartz.Server.

FIXES

  • Create zip package as part of release, including Quartz.Server (#572)
  • A specific CronExpression fails with "Input string was not in a correct format." (#568)
  • Cannot use remoting due to Task and CancellationToken signatures (#571)
+ + + diff --git a/2018/01/25/quartznet-3-0-2-released/index.html b/2018/01/25/quartznet-3-0-2-released/index.html new file mode 100644 index 000000000..3e5ce4297 --- /dev/null +++ b/2018/01/25/quartznet-3-0-2-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.0.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2018/02/24/quartznet-3-0-3-released/index.html b/2018/02/24/quartznet-3-0-3-released/index.html new file mode 100644 index 000000000..23a01ebe4 --- /dev/null +++ b/2018/02/24/quartznet-3-0-3-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.0.3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a minor fix release.

FIXES

  • XML scheduling requires write access to source XML file (#591)
  • Improve listener error handling (#589)
  • SQL command parameters are not defined in 'IsTriggerStillPresent' method (#579)
  • Source distribution couldn't be built with build.cmd/.sh when no .git directory present (#596)
  • Currently executing jobs cannot be retrieved via remoting (#580)
+ + + diff --git a/2018/03/04/quartznet-3-0-4-released/index.html b/2018/03/04/quartznet-3-0-4-released/index.html new file mode 100644 index 000000000..ab69113b7 --- /dev/null +++ b/2018/03/04/quartznet-3-0-4-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 3.0.4 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release fixes a nasty memory leak caused by QuartzSchedulerThread sharing its CancellationTokenSource with calls it makes. +Everyone using 3.x is advised to upgrade.

FIXES

  • Memory leak caused by CancellationTokenSource sharing (#600)
  • tables_oracle.sql should use NUMBER(19) instead of NUMBER(13) for long properties (#598)
+ + + diff --git a/2018/05/27/quartznet-2-6-2-released/index.html b/2018/05/27/quartznet-2-6-2-released/index.html new file mode 100644 index 000000000..c055c7693 --- /dev/null +++ b/2018/05/27/quartznet-2-6-2-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 2.6.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2018/05/27/quartznet-3-0-5-released/index.html b/2018/05/27/quartznet-3-0-5-released/index.html new file mode 100644 index 000000000..49f33b0f6 --- /dev/null +++ b/2018/05/27/quartznet-3-0-5-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.0.5 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release fixes couple bugs and adds support for .NET Core version of Oracle's managed data access library.

NEW FEATURE

  • Support Oracle.ManagedDataAccess.Core (#609)

FIXES

  • trigger loop encountered using DailyTimeIntervalTrigger across DST start boundary (#610)
  • Missing ConfigureAwait(false) in some parts of code (#618)
+ + + diff --git a/2018/07/06/quartznet-3-0-6-released/index.html b/2018/07/06/quartznet-3-0-6-released/index.html new file mode 100644 index 000000000..e6bd1c3ef --- /dev/null +++ b/2018/07/06/quartznet-3-0-6-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 3.0.6 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release fixes a nasty bug with JSON calendar database serialization and .NET Core SQL Server client libraries +have been updated to mitigiate possible hangs when connection drops occur.

Also some other minor bugs have been also addressed.

You should now be able to debug into Quartz.NET sources with added SourceLink support.

NEW FEATURE

  • Add SourceLink support (#642)
  • Make JobInterrupted method virtual in class SchedulerListenerSupport (#631)

FIXES

  • Trigger group can be left as paused when all triggers have been removed (#641)
  • PlatformNotSupportedException on RaspberryPi (Windows IoT) (#630)
  • JSON serialisation returning defaults for derived calendar settings (#634)
  • .NET Core version not able to recover from DB connection drops (#637)
+ + + diff --git a/2018/10/07/quartznet-3-0-7-released/index.html b/2018/10/07/quartznet-3-0-7-released/index.html new file mode 100644 index 000000000..ded5e0aee --- /dev/null +++ b/2018/10/07/quartznet-3-0-7-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 3.0.7 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release brings .NET Core 2.1 version of example server and adds new plugin +Quartz.Plugins.TimeZoneConverter which allows usage of TimeZoneConverter library (opens new window) to get consistent time zone id parsing between +Linux and Windows.

There are also some bug fixes related to AdoJobStore.

NEW FEATURE

FIXES

  • Added transient codes from EF into new JobStore (#681)
  • Parametrized queries produced by ReplaceTablePrefix should be cached (#651)
  • Use TypeNameHandling.Auto for JsonObjectSerializer (#621)
  • Fix a race condition that could cause duplicate trigger firings (#690)
  • ISchedulerListener.JobScheduled not called when scheduling multiple jobs (ScheduleJobs) (#678)
+ + + diff --git a/2020/07/06/website-refresh/index.html b/2020/07/06/website-refresh/index.html new file mode 100644 index 000000000..63b0d070e --- /dev/null +++ b/2020/07/06/website-refresh/index.html @@ -0,0 +1,55 @@ + + + + + + Website refresh | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2020/07/08/quartznet-3-1-beta-1-released/index.html b/2020/07/08/quartznet-3-1-beta-1-released/index.html new file mode 100644 index 000000000..04a26022b --- /dev/null +++ b/2020/07/08/quartznet-3-1-beta-1-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.1 beta 1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Quartz.NET 3.1 beta 1 Released

The wait is almost over, after more than two years of hiatus, Quartz.NET 3.1 beta 1 is here with exciting new features. This release concentrates on performance and bringing support to de facto Microsoft libraries like dependency injection and ASP.NET Core hosting.

# Support for ASP.NET Core Dependency Injection and Hosted Services

You can find the revisited packages as:

I would like to thank both Facundo Glaeser (opens new window) and Lewis Zou (opens new window) for working with the new integration packages and their logistics.

The best resource the see the new DI integration in progress is to head to the example ASP.NET Core application (opens new window).

# Index and query performance improvements

A big change on the persistent store side is that now SQL queries use parametrized scheduler name, which allows database server to reuse query plans and use indexes more optimally. This will help especially clusters which have large number of nodes. The SQL server indexes were also revisited and their amount reduced by using smarter covering indexes.

See the updated create index definition (opens new window) for more details.

There are also some minor bug fixes present.

# Known Issues

The documentation for the new integration features is still being worked on.

# GitHub Issues

BREAKING CHANGES

  • minimum supported .NET Full Framework is now 4.6.1

NEW FEATURE

  • Microsoft DI integration via package Quartz.Extensions.DependencyInjection (also allows briding to Microsoft Logging)
  • ASP.NET Core / Hosting integration and health checks via revisited NuGet package Quartz.AspNetCore (thank you zlzforever for contributing the work)
  • Introduced a config parameter ClusterCheckinMisfireThreshold (#692)
  • Giving meaningful names to examples folders (#701)
  • Added search patterns/sub directory search to directoty scanner job (#411, #708)
  • Fluent interface for scheduler configuration (#791)
  • Support every nth week in cron expression (#790)
  • Enable SQLite job store provider for NetStandard (#802)
  • Add configurable params for StdRowLockSemaphore for Failure obtaining db row lock
  • SchedName added to queries as sql paramteter (#818)
  • Server, example and test projects upgraded to user .NET Core 3.1
  • Nullable reference type annotations have been enabled
  • Symbols are now provided as a separate NuGet symbol package (snupkg)
  • SQL Server indexes have been fine-tuned, redudancies were removed and you can follow the current scripts to update to latest version of them

FIXES

  • Allow binary serialization for DirectoryScanJob data (#658)
  • LibLog - Fixed NLog + Log4net callsite. Added support for NLog structured logging. Optimized Log4net-logger (#705)
  • Upgrade LibLog to latest version (#749)
  • RAMJobStore performance improvements (#718, #719, #720)
  • General performance improvements (#725, #723, #727)
  • GetTimeBefore() and GetFinalFireTime() should throw NotImplementedException instead of returning null (#731)
  • Switch to official TimeZoneConverter NuGet package (#739)
  • Remove invalid TimeSpanParseRule.Days (#782)
  • Update tables_sqlServer.sql to follow current SQL syntax and structures (#787)
  • Fix China Standard Time mapping in TimeZoneUtil.cs (#765)
  • Release BLOCKED triggers in ReleaseAcquiredTrigger (#741 #800)
  • DailyTimeIntervalTrigger failed to set endingDailyAfterCount = 1
  • CronTrigger: cover all valid misfire policies, and provide a sensible default and logging when seeing an invalid one
+ + + diff --git a/2020/07/14/quartznet-3-1-beta-2-released/index.html b/2020/07/14/quartznet-3-1-beta-2-released/index.html new file mode 100644 index 000000000..9f6076ffa --- /dev/null +++ b/2020/07/14/quartznet-3-1-beta-2-released/index.html @@ -0,0 +1,57 @@ + + + + + + Quartz.NET 3.1 beta 2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Quartz.NET 3.1 beta 2 Released

The wait is almost over, after more than two years of hiatus, Quartz.NET 3.1 beta 2 is here with exciting new features. +This release builds on top of beta 1 adding more fixes and improvements. Read the beta 1 release notes to know more.

# Known Issues

The documentation for the new integration features is still being worked on.

# GitHub Issues

NEW FEATURE

  • DI configuration now supports adding scheduler, job and trigger listeners (#877)
  • DI configuration now processes appsettings.json section "Quartz" looking for key value pairs (#877)
  • Use Microsoft.Data.SqlClient as SQL Server connection library (#839)

FIXES

  • Fix potential scheduler deadlock caused by changed lock request id inside ExecuteInNonManagedTXLock (#794)
  • Ensure NuGet.exe is part of produced zip to ensure build works (#881)
  • JobDataMap with enum values persisted as JSON can now be set back to job members via PropertySettingJobFactory (#770)
  • Ensure GetScheduleBuilder for triggers respects IgnoreMisfirePolicy (#750)
  • Remove cron expression validation from XML schema and rely on CronExpression itself (#729)
+ + + diff --git a/2020/07/21/quartznet-3-1-beta-3-released/index.html b/2020/07/21/quartznet-3-1-beta-3-released/index.html new file mode 100644 index 000000000..046482888 --- /dev/null +++ b/2020/07/21/quartznet-3-1-beta-3-released/index.html @@ -0,0 +1,63 @@ + + + + + + Quartz.NET 3.1 beta 3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Quartz.NET 3.1 beta 3 Released

The wait is almost over, after more than two years of hiatus, Quartz.NET 3.1 beta 2 is here with exciting new features. +This release builds on top of beta 1 and beta 2 adding more fixes and improvements.

Read the beta 1 release notes and beta 2 release notes to know more.

# Known Issues

The documentation for the new integration features is still being worked on.

# GitHub Issues

NEW FEATURE

* Upgrade MySqlConnector to 1.0 (namespace has changed) (#890)
+* Support Microsoft.Extensions.Logging.Abstractions (#756)
+* Support Microsoft.Data.SQLite with full framework (#893)
+* Support custom calendar JSON serialization (#697)
+

FIXES

* Remove internal dependencies from examples (#742)
+* Properly assign MaxConcurrency in CreateVolatileScheduler (#726)  
+
+ + + diff --git a/2020/07/21/quartznet-3-1-released/index.html b/2020/07/21/quartznet-3-1-released/index.html new file mode 100644 index 000000000..558b1f740 --- /dev/null +++ b/2020/07/21/quartznet-3-1-released/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET 3.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2020/07/24/quartznet-3-1-released/index.html b/2020/07/24/quartznet-3-1-released/index.html new file mode 100644 index 000000000..c5fefe93f --- /dev/null +++ b/2020/07/24/quartznet-3-1-released/index.html @@ -0,0 +1,68 @@ + + + + + + Quartz.NET 3.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release concentrates on performance and bringing support for standard integrations. +Quartz 3.1 supports netstandard2.0 and net461 targets (for integrations they may be different).

# New Integrations

# Support for ASP.NET Core Dependency Injection and Hosted Services

New NuGet packages ASP.NET Core Integration and Quartz.Extensions.DependencyInjection +finally bring built-in support for integrating Quartz.NET with reliable manner with the Microsoft DI container and hosted services infrastructure.

The best resource the see the new DI integration in progress is to head to the example ASP.NET Core application (opens new window).

I would like to thank both Facundo Glaeser (opens new window) and Lewis Zou (opens new window) for working with the new integration packages and their logistics.

# OpenTelemetry Integration

New experimental NuGet package Quartz.OpenTelemetry.Instrumentation brings support for emerging OpenTelemetry standard.

First version of integration is able transmit job execution (Started, Ended, Exception) information to exporters. With this infrastructure is should also be easier to implement job history +using battle-tested log backends for storing data. The example ASP.NET Core application (opens new window) integrates +with Jaeger and transmits this data.

# Database

# Better Indexes for SQL Server and smarter parametrized queries

A big change on the persistent store side is that now SQL queries use parametrized scheduler name, which allows database server to reuse query plans and use indexes more optimally. +This will help especially clusters which have large number of nodes. The SQL server indexes were also revisited and their amount reduced by using smarter covering indexes.

See the updated create index definition (opens new window) for more details.

TIP

You need to re-run the index script to take advantage of changes, this will drop old indexes and rebuild/create new ones, it can be time-consuming!

# Bug fix for cluster locking

There is also a very important bug fix present for lock handling on retries. There was a possibility for a deadlock in cluster's database lock handling in some situations.

# Microsoft.Data.SqlClient as SQL Server connection library

Quartz now uses Microsoft.Data.SqlClient (opens new window) as the connection library for SQL Server as it's the one going to get new features. +It is dependency for Quartz library (for now) so you shouldn't need to do any manual install steps.

# Upgrade MySqlConnector to 1.0 (namespace has changed)

You need to use the latest MySqlConnector 1.0.0 (opens new window) in order to use with default Quartz configuration. +As the namespace for library has changed it's not backwards compatible. +If you need to use the old version, you should manually register DB provider with the old details.

# Known Issues

No known issues. Documentation might require additions and community contributions are welcomed. Edits should be easy now with the new publishing framework.

# GitHub Issues

BREAKING CHANGES

  • minimum supported .NET Full Framework is now 4.6.1
  • changed SQL commands format in Quartz.Impl.AdoJobStore.JobStoreSupport (see also #818 (opens new window)). Affected are only schedulers that use customized configurations of SQL commands in Quartz.Impl.AdoJobStore.JobStoreSupport, e.g. SelectWithLockSQL. Migration example:
<!-- Quartz <=3.0.7 -->
+<item key="quartz.jobStore.selectWithLockSQL">SELECT * FROM {0}LOCKS WITH (UPDLOCK,ROWLOCK) WHERE SCHED_NAME = {1} AND LOCK_NAME = @lockName</item>
+<!-- Quartz >=3.1.0 -->
+<item key="quartz.jobStore.selectWithLockSQL">SELECT * FROM {0}LOCKS WITH (UPDLOCK,ROWLOCK) WHERE SCHED_NAME = @schedulerName AND LOCK_NAME = @lockName</item>
+

NEW FEATURE

  • Microsoft DI integration via package Quartz.Extensions.DependencyInjection (also allows bridging to Microsoft Logging)
  • DI configuration now supports adding scheduler, job and trigger listeners (#877)
  • DI configuration now processes appsettings.json section "Quartz" looking for key value pairs (#877)
  • Add diagnostics source and OpenTelemetry support (#901)
  • Use Microsoft.Data.SqlClient as SQL Server connection library (#839)
  • ASP.NET Core / Hosting integration and health checks via revisited NuGet package Quartz.AspNetCore (thank you zlzforever for contributing the work)
  • Introduced a config parameter ClusterCheckinMisfireThreshold (#692)
  • Giving meaningful names to examples folders (#701)
  • Added search patterns/sub directory search to directory scanner job (#411, #708)
  • Fluent interface for scheduler configuration (#791)
  • Support every nth week in cron expression (#790)
  • Enable SQLite job store provider for NetStandard (#802)
  • Add configurable params for StdRowLockSemaphore for Failure obtaining db row lock
  • SchedName added to queries as sql parameter (#818)
  • Server, example and test projects upgraded to user .NET Core 3.1
  • Nullable reference type annotations have been enabled
  • Symbols are now provided as a separate NuGet symbol package (snupkg)
  • SQL Server indexes have been fine-tuned, redundancies were removed and you can follow the current scripts to update to latest version of them
  • Upgrade MySqlConnector to 1.0 (namespace has changed) (#890)
  • Support Microsoft.Extensions.Logging.Abstractions (#756)
  • Support Microsoft.Data.SQLite with full framework (#893)
  • Support custom calendar JSON serialization (#697)
  • DI configuration now supports adding scheduler, job and trigger listeners (#877)
  • DI configuration now processes appsettings.json section "Quartz" looking for key value pairs (#877)
  • Use Microsoft.Data.SqlClient as SQL Server connection library (#839)

FIXES

  • Allow binary serialization for DirectoryScanJob data (#658)
  • LibLog - Fixed NLog + Log4net callsite. Added support for NLog structured logging. Optimized Log4net-logger (#705)
  • Upgrade LibLog to latest version (#749)
  • RAMJobStore performance improvements (#718, #719, #720)
  • General performance improvements (#725, #723, #727)
  • GetTimeBefore() and GetFinalFireTime() should throw NotImplementedException instead of returning null (#731)
  • Switch to official TimeZoneConverter NuGet package (#739)
  • Remove invalid TimeSpanParseRule.Days (#782)
  • Update tables_sqlServer.sql to follow current SQL syntax and structures (#787)
  • Fix China Standard Time mapping in TimeZoneUtil.cs (#765)
  • Release BLOCKED triggers in ReleaseAcquiredTrigger (#741 #800)
  • DailyTimeIntervalTrigger failed to set endingDailyAfterCount = 1
  • CronTrigger: cover all valid misfire policies, and provide a sensible default and logging when seeing an invalid one
  • Remove internal dependencies from examples (#742)
  • Properly assign MaxConcurrency in CreateVolatileScheduler (#726)
  • Fix potential scheduler deadlock caused by changed lock request id inside ExecuteInNonManagedTXLock (#794)
  • Ensure NuGet.exe is part of produced zip to ensure build works (#881)
  • JobDataMap with enum values persisted as JSON can now be set back to job members via PropertySettingJobFactory (#770)
  • Ensure GetScheduleBuilder for triggers respects IgnoreMisfirePolicy (#750)
  • Remove cron expression validation from XML schema and rely on CronExpression itself (#729)
+ + + diff --git a/2020/10/01/quartznet-3-2-released/index.html b/2020/10/01/quartznet-3-2-released/index.html new file mode 100644 index 000000000..58a074f36 --- /dev/null +++ b/2020/10/01/quartznet-3-2-released/index.html @@ -0,0 +1,105 @@ + + + + + + Quartz.NET 3.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release concentrates on tweaking the DI story and fixing some found dependency issues.

# Quartz.Extensions.Hosting

A new package Quartz.Extensions.Hosting (opens new window) +was created with the help of Andrew Lock (opens new window). If you are using generic host and you don't need +ASP.NET specific functionality like health checks, you can switch to this new package to reduce dependencies.

# Refining DI integration API

Some work was done to improve the MS DI integration API.

# Options pattern

Now the API uses options pattern (opens new window) +properly and you can attach your own configurators to alter QuartzOptions.

// we can use options pattern to support hooking your own configuration
+// because we don't use service registration api
+// we need to manally ensure the job is present in DI
+services.AddTransient<ExampleJob>();
+            
+services.Configure<SampleOptions>(Configuration.GetSection("Sample"));
+services.AddOptions<QuartzOptions>()
+    .Configure<IOptions<SampleOptions>>((options, dep) =>
+    {
+        if (!string.IsNullOrWhiteSpace(dep.Value.CronSchedule))
+        {
+            var jobKey = new JobKey("options-custom-job", "custom");
+            options.AddJob<ExampleJob>(j => j.WithIdentity(jobKey));
+            options.AddTrigger(trigger => trigger
+                .WithIdentity("options-custom-trigger", "custom")
+                .ForJob(jobKey)
+                .WithCronSchedule(dep.Value.CronSchedule));
+        }
+    });
+
+

# ScheduleJob

A new shorthand was created to quickly define a job with trigger using a single call.

q.ScheduleJob<ExampleJob>(trigger => trigger
+    .WithIdentity("Combined Configuration Trigger")
+    .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(7)))
+    .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second))
+    .WithDescription("my awesome trigger configured for a job with single call")
+);
+

# AddCalendar

You can now add calendars using the DI API.

const string calendarName = "myHolidayCalendar";
+q.AddCalendar<HolidayCalendar>(
+    name: calendarName,
+    replace: true,
+    updateTriggers: true,
+    x => x.AddExcludedDate(new DateTime(2020, 5, 15))
+);
+
+q.AddTrigger(t => t
+    .WithIdentity("Daily Trigger")
+    .ForJob(jobKey)
+    .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(5)))
+    .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second))
+    .WithDescription("my awesome daily time interval trigger")
+    .ModifiedByCalendar(calendarName)
+);
+

# Microsoft SQL Server

Now Quartz no longer has hard dependency on Microsoft.Data.SqlClient package. +Full framework defaults now back to same behavior as it was with Quartz 3.0 (using built-in System.Data.SqlClient driver).

# Full Framework

You can use either one of the two providers, SqlServer (default) or SystemDataSqlClient. Former uses System.Data.SqlClient and latter +the new Microsoft.Data.SqlClient package (opens new window). +If you choose to use the new package, make sure you have the NuGet package installed.

# .NET Core

You need to ensure you have Microsoft.Data.SqlClient package (opens new window) installed.

# Query plan cache pollution fix

There was an important fix for SQL Server where varying text parameter sizes caused query plan cache pollution. Now when no parameter size is +defined for string parameter, default value of 4000 will be used. This problem has been present since the beginning.

# GitHub Issues

BREAKING CHANGES

  • Remove dependency on Microsoft.Data.SqlClient (#912)
  • LogContext moved from Quartz namespace to Quartz.Logging namespace (#915)
  • For Full Framework, System.Data.SqlClient is again the default provider, Microsoft.Data can be used via provider MicrosoftDataSqlClient (#916)

NEW FEATURE

  • Introduce separate Quartz.Extensions.Hosting (#911)
  • You can now schedule job and trigger in MS DI integration with single .ScheduleJob call (#943)
  • Support adding calendars to MS DI via AddCalendar<T> (#945)

FIXES

  • Revert change in 3.1: CronExpression/cron trigger throwing NotImplementedException when calculating final fire time (#905)
  • Use 2.1 as the minimum version for the .NET Platform Extensions (#923)
  • ServiceCollection.AddQuartz() should register default ITypeLoadHelper if none supplied (#924)
  • SqlServer AdoJobStore SqlParameter without text size generates pressure on server (#939)
  • DbProvider initialization logic should also read quartz.config (#951)
  • LoggingJobHistoryPlugin and LoggingTriggerHistoryPlugin names are null with IoC configuration (#926)
  • Improve options pattern to allow better custom configuration story (#955)
+ + + diff --git a/2020/10/18/quartznet-3-2-1-released/index.html b/2020/10/18/quartznet-3-2-1-released/index.html new file mode 100644 index 000000000..3118e3338 --- /dev/null +++ b/2020/10/18/quartznet-3-2-1-released/index.html @@ -0,0 +1,59 @@ + + + + + + Quartz.NET 3.2.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a maintenance release containing mostly bug fixes.

MS dependency injection job factory configuration was unified and you can now configure relevant options +like whether to create a separate scope with using just the UseMicrosoftDependencyInjectionJobFactory and its callback. +Now scoped jobs also get their properties set from job data map.

Pre-configuring Quartz options from appsettings.json with services.Configure<QuartzOptions>(Configuration.GetSection("Quartz")); +now also works as expected.

# GitHub Issues

FIXES

  • Make QuartzOptions Triggers and JobDetails public (#981)
  • Fix configuration system injection for dictionary/quartz.jobStore.misfireThreshold in DI (#983)
  • XMLSchedulingDataProcessor can cause IOException due to file locking (#993)

IMPROVEMENTS

  • Unify MS dependency injection job factory logic and configuration (#995)
  • Improve job dispatch performance to reduce latency before hitting Execute (RAMJobStore) (#996)
+ + + diff --git a/2020/10/19/quartznet-3-2-2-released/index.html b/2020/10/19/quartznet-3-2-2-released/index.html new file mode 100644 index 000000000..64f550632 --- /dev/null +++ b/2020/10/19/quartznet-3-2-2-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.2.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2020/10/31/quartznet-3-2-3-released/index.html b/2020/10/31/quartznet-3-2-3-released/index.html new file mode 100644 index 000000000..96ed51549 --- /dev/null +++ b/2020/10/31/quartznet-3-2-3-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 3.2.3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release addresses issue with Autofac integration and adds new integration package +Quartz.OpenTracing to allow +integration with OpenTracing contributed by Pavel Stefanov (opens new window).

# GitHub Issues

NEW FEATURE

  • Add Quartz.OpenTracing support (#1006)
  • Add UseZeroSizeThreadPool to configuration (#1003)

FIXES

  • Xamarin Android can't get scheduler (#1008)
  • Autofac job factory registration fails (#1011)
+ + + diff --git a/2021/01/19/quartznet-3-2-4-released/index.html b/2021/01/19/quartznet-3-2-4-released/index.html new file mode 100644 index 000000000..e73e5e0bb --- /dev/null +++ b/2021/01/19/quartznet-3-2-4-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 3.2.4 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release is a maintenance release with couple of bug fixes. The most important fix for this release is that +now Quartz distinguishes between external code task cancellation (say HttpClient) and job cancellation triggered by using +the Quartz API's Interrupt method. Earlier Quartz incorrectly considered also other OperationCanceledExceptions as clean instead of being errors.

# GitHub Issues

FIXES

  • JobRunShell silently handles OperationCanceledException which is not correct in terms of job retry handling (#1064)
  • Handled exceptions thrown while retrieving the misfired trigger (#1040)
  • FileScanJob is faling after upgrading from 3.0.7 to 3.2.3 (#1027)
  • JobBuilder.UsingJobData(string key, string value) should be JobBuilder.UsingJobData(string key, string? value) (#1025)
+ + + diff --git a/2021/04/07/quartznet-3-3-released/index.html b/2021/04/07/quartznet-3-3-released/index.html new file mode 100644 index 000000000..b953c1026 --- /dev/null +++ b/2021/04/07/quartznet-3-3-released/index.html @@ -0,0 +1,60 @@ + + + + + + Quartz.NET 3.3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release addresses problems with using Quartz with .NET Full Framework lower than 4.7.2. ValueTask loading +could fail due the dependencies brought with activity source support. Now activity sources are only supported when +using .NET Framework >= 4.7.2 and netstandard >= 2.0. This also raises requirement the same way for package +Quartz.OpenTelemetry.Instrumentation.

This release also improves trigger acquisition performance when using persistent job store, mostly by reducing network round-trips. +The semaphore implementations were also re-written to gain more performance.

Also some bug fixes included, thanks to all contributors!

# GitHub Issues

BREAKING CHANGES

  • Activity source listener is not longer part of net461 build, only net472
  • Quartz.AspNetCore integration package minimum .NET Core version is now 3.1 for HealthChecks support

NEW FEATURES

  • Separate build configuration for .NET Framework 4.7.2
  • OpenTelemetry integration upgraded to target OpenTelemetry 1.0.0-rc1.1
  • Ported JobInterruptMonitorPlugin from Java version which allows automatic interrupt calls for registered jobs (#1110)
  • Rewrite semaphore implementations (#1115)
  • UsingJobData now has Guid and char overloads (#1141)
  • Add a regular AddJob(Type) (#1090)

FIXES

  • Jobs not firing after upgrade to 3.2.x (from 3.0.7) on Microsoft Server 2008 R2 (#1083)
  • Jobs are not fired (#1072)
  • MicrosoftDependencyInjectionJobFactory does not inject job properties for scoped jobs (#1106)
  • XSD schema no longer requires defining durable element if you just want to define recover (#1128)
  • Stack trace logging fixed in case of reporting invalid lock acquire (#1133)
  • Disposable job is disposed twice when using UseMicrosoftDependencyInjectionScopedJobFactory (#1120)
  • QuartzHostedService.StopAsync throws NullReferenceException if StartAsync hasn't been run (#1123)
+ + + diff --git a/2021/04/08/quartznet-3-3-1-released/index.html b/2021/04/08/quartznet-3-3-1-released/index.html new file mode 100644 index 000000000..4bbd76907 --- /dev/null +++ b/2021/04/08/quartznet-3-3-1-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.3.1 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/2021/04/09/quartznet-3-3-2-released/index.html b/2021/04/09/quartznet-3-3-2-released/index.html new file mode 100644 index 000000000..876d5e2a7 --- /dev/null +++ b/2021/04/09/quartznet-3-3-2-released/index.html @@ -0,0 +1,58 @@ + + + + + + Quartz.NET 3.3.2 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This release returns the possibility to resolve jobs from Microsoft DI container. Now container is checked first and if not found then +ActivatorUtilities is used to construct the type with constructor injection support. Now both AllowDefaultConstructor and CreateScope have +been obsoleted as behavior is now either via DI construction or ActivatorUtilities and scope is always created to prevent resource leaks / double disposal.

Also a problem with host name resolution under WSL2 scenario was fixed.

FIXES

  • Try resolving jobs from service provider before resorting to ActivatorUtilities (#1159)
  • Can't get hostname on WSL2+docker host network (#1158)
+ + + diff --git a/2021/08/01/quartznet-3-3-3-released/index.html b/2021/08/01/quartznet-3-3-3-released/index.html new file mode 100644 index 000000000..7468b46bc --- /dev/null +++ b/2021/08/01/quartznet-3-3-3-released/index.html @@ -0,0 +1,56 @@ + + + + + + Quartz.NET 3.3.3 Released | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This is a maintenance release mostly fixing some smaller bugs and improving DI API story.

FIXES

  • Lock 'TRIGGER_ACCESS' attempt to return by: de9325af-3e1c-4ae9-a99b-24be994b75f4 -- but not owner! (#1236)
  • ScheduleJob shorthand: Job name should match trigger name by default (#1211)
  • CronTriggerImpl.WillFireOn returns wrong result when TimeZone is specified (#1187)
  • Race condition in DI scheduler listener initialization (#1117)
  • JobRunShell handle Job CancellationToken (#1183)
  • Restore System.Data.SqlClient support on .NET Core (#1181)

IMPROVEMENTS

  • Replace static loggers with instance-based (#1264)
  • Expose more configuration options via programmatic APIs (#1263)
  • Add ConfigureScope extension point to MicrosoftDependencyInjectionJobFactory (#1189)
  • Update StdAdoConstants.cs (#1186)
  • Use custom InstantiateType for all instantiations in StdSchedulerFactory (#1185)
  • Add support for the ISchedulerFactory.StartDelayed in the QuartzHostedService (#1166)
  • Remove SimpleThreadPool from examples? (#1230)
+ + + diff --git a/404.html b/404.html new file mode 100644 index 000000000..d0f3e6f7e --- /dev/null +++ b/404.html @@ -0,0 +1,33 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

404

There's nothing here.
+ Take me home. +
+ + + diff --git a/android-icon-144x144.png b/android-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..93ee8cb09a215fd8dfdf0976d4672dc5abd35651 GIT binary patch literal 19676 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 FzX9@)T8{t# literal 0 HcmV?d00001 diff --git a/android-icon-192x192.png b/android-icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..17c89e03a594dcc6fe1af66c286bae18190dc7c4 GIT binary patch literal 27792 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 JtvyD#^e-=rRr>${ literal 0 HcmV?d00001 diff --git a/android-icon-48x48.png b/android-icon-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..15877c66310d8fbdc133ab3e146e5b75c5ee9dc9 GIT binary patch literal 4487 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 dxPmlVf>a?vT3@~40})aOKG1#n literal 0 HcmV?d00001 diff --git a/android-icon-72x72.png b/android-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..66a15d8307245d32954810c754304f31e434ffbd GIT binary patch literal 7366 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 HY-9fmA@zu| literal 0 HcmV?d00001 diff --git a/android-icon-96x96.png b/android-icon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..9403db8c95de60271ec43dfeec7075a94ee09d46 GIT binary patch literal 11073 zcmZ{K1yEc;^XD$^7A&{~LU4Bv8XOka;O?%wxFk5iJwRB32ME5ny9al7_v8E5Ro!=2 zb@i&>)Xe-^UcIUA>7I#FRhGp>BS8ZI0GRS}QtEH5$$tn1>FvFd=EeWkAXrH#NdN%V zap+H95#RbiH+5M_K*cE8{#%F2Oio=10Pv*;0KlODz{A@Rcn<*ZU@cN%8ueBuUZ3NX>PS*_p!0P%B0sEYOnF9a}f8?bkK;Hk3v%Rv+ zwLNy*ciXh{%`_wSbM`?qUuiNX7)DX(&>`XosP7fy>Ec6C2~F%PM>Y&A-!Ir@u@jTV zE8$T6flI;{Cq$7)*-qeQP|DfQDlRee@bc)n9er^rE1LaTkwevDG`g!n`Q6f}wdwZh zMBw(PU&R@ty5DEoZ_1q)Bx+^`@sZ-R<0$_ClUVKm7IAzAct-IqDjyR ztj_e#)Mq3nh^nyx2j=QX#E8D)L5LR&X9b;kYh%IIR!*m-88?ahKjFtGCZ%9Qi5?1) z(cCCm=q*_D7~DYIBeWnMhA_lUpS7>!vS5*5Wu}c+E5OE2;P?u09|GdYJJ7iqN~XjL zAS+^Kzr%P_IKTwW8+awL1_XKXZOxJJxCynY$__{{osfg0jDf zCF7%aUov>nE|qk?DE5ya)KV-jFIPT*l~KStX6WC)Yhqx3{L)iJ;hhP~gz$(Dl!<0; z48Y5PBOpTJLHqajAv7}0j}OK(5Hdc%@i{-e$r)!L%brD~0gKj{c5c6)vBej7KZ#RN z$|<^KoQmkKE$ZXLZ3`njf5k|Z2qC=lbfMvzo`fh(Cw*SDG8)F_fN_!M_c!!wD!K8S&0JCFUT-y+`QeL2(Eh$YQ>zu774`H@q7*RT>tab?3<< zt3qUuwU*V1is$aVvV?OiuKpQXoxY#MUrzh#JuyuY6A~FxnF$e-{EN|ipb~naqv;IT z>-7Cg%V5TsAw~B+zKc^hRGm?hKoxl!zPhsn4u#o6S(bQ6S@XH(SK!z?u6^j(%Zr8; z9f8RFjW-zrQ7$?}1xN&3-+Ws3sjWixCYeWS!X`%Ig0P32?#^7++1tzLb7=_Lelh>k zB=e-Mjq?qSu0W~>4i}ymkO}sHaZ6WZ1CD6pt*07P&h;~eB+7A~g47gNE{pni}cmdHi z5+gTs06FGyq*XWej>60yCuB-3K!j!&o~io$=Vn5*#M)(~|M#raJWj>kiq=X|KsgJ` zuZLJ%tE5POlEWF+lzV~kKoF(c9rl_F1peUB2lw-Cg4EM2Q^%M2L)>SFtm;(b}ohh(p`C)ig7^ z15FTG3#3RuOOzM?jB1bwq7S#H5uK#kjhkTmEwqeA(}aR<%?H5WO=m6_PL3XP(=S6qLtM|B$d9yi7Gsh9myx5u87cy1hjS?imefb7 z`G|A3nUp$3dU_QSfGoM9A2X5!QO!N?8ZC@eH)C`RAOt>z_kx_K2kJVzac%kkDVRLxxK^vSSDFg0!R*=?W#G-9la8ofSR( zS_m_9T@F|lZa2e*fMd*-1mYdT&~TpvAnindQP+{A`2IZaSHgji(DE(M#nq_<@Z$^Z z@McnBpEPC;R!)p|RYdOx)HeCOg6)BA!6Ve(3TqQcp{wwQP8YrI+`# z;k6w{b?u1|PX6#^7EWTe;)NEz3Vfe3pEhj=hRHg%B>0bx?bbkuAZ&nK#6U#+=8VrU zX{x!q*j4_w_%)3IW=;5p=?&Tya20S*#3LL-y*M)mFYaf?wN+EV z3v#K3QKCO#_CHEMj~T6q?@-UG1|CYGaZd!|Boo|Fd5{~xJEDwA(}JE))~GeH(SK+1 zckU~>v;u@o+$)GrLa7j!JfY>5-2b%}mZYPpiy;kR!U=F2Rr*0IO5`?x3V#+YlGjQn zn(GUNuYmP>MlZPUrU#)rGsW(6wLN5uEdSxHGt0s_5TbS&CV?~nojU)WAcG@R9gu8s z+rAGT7o3dm36aXT@WOef&_h0ap#ZJ~&3%RMfAC?1E6Rs2Esen{E)mrsMA^+$u#=VC zMYw1hfvbPb9SzT8GIxbUm-OWrdG4+ebx)B(&~=uaa6$=_%kTpz%n!vCQpZpqtl7$s zblkY26Sc*D?OED`YMc6R$pDVXj)=bJ{_V9Tne{&ir7)n%2>k3q>4^pds5z||8E%o*6!UGURn#7u>*OY@kr~;k!63jr+(l&C#2=@>tG^UqILUFrho~-LW=Xd zsM3Pe4=@61(hAx%(RsKQavdcX&&v;IpTnFUBy)ks2mATut>lTHP%?c%6@=cDv!4U- zubN>=G>Qy=AWL*rUCBc4UY8!oo0|L}Q|MhoR^q*2fvsOVaccYlr^Dm2r($QFMHMdU znYLQTsKi#TZpXHP^N-%ZVSBo?G6_cna)pK;Vku=9OQ*`agFPptmAd|;>R|_&2sy(s zjeU24tSgg>V=m#<#)$w4lp^eK@FfoG&%fS*NZu${nKJI}g$G{OSK}*7ov;Wt2}y{h znke;|tWMlj8Ps0w`gGv_1t{ejc|{{!MDxyQvaq(fuT2+tE%9Eu5!=G+Yh(M>W|)#T zm?y+-lkzn#-@(bp)m}x{p=twGF8B&Q=otO>ZyHFuXziGh=6zt7LOxQF$w12$5#lG5 zbn%dq7ug`51)pnep&+A)Y~lW9J8cX7FLuokc$L_b_49;fESXW{Xa3prN3t`G3&@9U zfpCg{%K8fEdCQTFhVdTrc`K$vO$1xlc`Ah`&VCA9*?sxpiYBAT;vlmgrh*Lh4?5?-owp}UH#(spV6#61N zS4HM0!|l?#W<>A)A~Vj907^f%L=v={j*JF|oj#^LCtKlOb0`Cz{N>iJVUN}8A!CJ0 z$JFW1AE~pN!S_SpL*(6FvAgmUWZOW_D{g_+!p1*8Qc^GrCrlP7sFeKOXr1XgF*;XG zhd)#4u6Pk;-Pe3tB*fY*OKc$U5(6#|QmcF69{@%P83^)3DD(vZ!5xtrXs%e&6@g*0 z;0WpGEFy#+unWSlV7whm$kk$-Gf~0*0u1#skowXNQueWS0Q)8HHHx6&`YCb$hzz({ z1Fh-M*KIQe946fnqf$4$yQ7iGk>MHR@uIjnLB2UIEUP3UQvHLz?Pxz4$iaxr8^Q}U z98y4rMdr~A;TXm6^boEid@fj0SRun9Fi=4Y3l8LQrgP>!i|@RB_~=WonUXM?lhpIX zxJK@FKO7Or`(*!AmVL{SoPhut6i2mV%vAqgG~)+3@8t6n4?=iR_8$|%yChO)$o>31 z6X=7GS*ycrWDdTDk%a8R{r<+HgtpXj8Ws6l(wsbIH!@)DeSBZ{fZv+r3bM1>sFXJ? zJCZ+95tGr(mtG-9_;uACZGh9j{YpfA?5W{%%JXfy$W%yJ5Z;f7GJX+~To$)3zdW3p zww=Bner>ji(fqIfOkF^Gh$lpc)NF(ThDfgUoowLH_U`-l$OgE&G37G`--^X4rJiwd zaIlTVrOPypIE_!?mlm(I>B*?UN#k6xoBvRPXAW7r*fs62J zWR2E1x_E@@iH5ns%(yN}cQzGj6`^;KvFp*&qHo~)yM?pbVV_H3t-&Q6(lWhPi+nlk zEFJgWTLcM-H&@Taj8zP9$)ighs-FItsrD0BpQbHsITJZYX8$%I;Qp)Gp!g`Fjp{sf z?*`m)*;0hI$z;=U-~_kA^&{P9U0@V_9)?+1eos0m1*3jHzu?t%qh5)WMDwA z?82x&*26pq@lP3ZE7mLk6QAgs4Cw~<>f%>kTiyoA?>i5ME1IJV?U#;$FAIo}n2WaC z7l(J*=J>OW2ud1%d*aV4ou^k6s#_Vy85+#y%|m!ZW2ITg!Rq<2 z!CCK#c8jXAc4CEAbYe+F14;?p7QAF0aVZnz{;Jy3n2+vTrV`*|Zq4Vlw)Fh(4erZM z6y(eDvtrY~)NF$Ze#iB;$mO{M^n0AiX76x&sq;Fy&)|9lEUpWrq#ZC^J^|cS4Wc%1 z_7L_u3t;S$$exHtTr?VyG%@y4mmL0@ENU~ZnjSl^72--TOyo(8)TNb2xwV{pE4iI1 zS#R7wKW3__@l?=jl7jDjBoC}!W@H#LM~kZS2x(`oQPhO4H-c7seA{DyYmnH;hgvG{ zHWPo<&y6~l9)#|ynwNlV5$Qg^4De9Z{mNU`BnWH9TWIupG2ctSIK2{8pLfU3O|~Ob zj;SBlGvY&UvF>wmmGif#paBe~p=dBW(#@(nn|q*2?x`CH_>h<@_G}&3Ba?`C7os%- zm7tuXlRZI5c92#~{iqv$_UxOQIbq?Z!k4ng(?UDXt^O_zIud3JjSEU=Hdfu-DN$=9N z`3hn1^JLwKu=JdV#@&y8jBPcqqB)rdqC2*Dxc-{z_lgeEc~^!y1XuX+2An9XeniQd zFn7tbn&K&bdyZ7t`&<8Xe$JWWgNF0DI4huXgoCIe&AYBnQ8pS!z{u=n|DP}MHal0f&^$>~S z{Yj>|Ps=<=@Glh|Gb=EMVIj3fjcvD=yjpM({(=)*3HOgUnhf|6tROQLRqu2w+)WOz zpFUDTM6RVQlJkCbOvf@KXCb8MG|JF<;-8#GKtDnT zyC(U_vjQ={en;=Pd>vpy7e4sO*<;@c7kaokLDxgO1a}#0bbNI&H1Y)ha8Y;}Q7nx% zdalmnGG^X5%}P`ZH8U5_gU*!fRb4dfa?50T~UOk@1}L{Nv_ge2_ZFs*cfI(u@%%f<;@bmmo-iW>li% zkp^)-4G}W`EK;?|L!eq!Yil{pxa-*@EvW7--+c7;^`{INP%CzGn|(~_p)(yFI-B2P z?d6=pD55Vsjm{48Y585Tf?G@Wmy3j%bVkKda;tA}$N_5&1=tYVOMHOFFe0Z$K;uJI zE}t6AW5f;MVs;e$0Z`NYhLZCT?5CZY+s-H&CDL98_luM5)?Ehw&b8{H3lGubFy{oVTEKO?V` zaBF*A*k4Ro19+v2cb7I^kW(y)(_Yb*V-TQwEdi(C){SM-HPKfl+^cU52oR?j$Xiv?#wZ1h5bL!b6FJY zu2t9A#n1%#)yKYmyO*@^%*sJ=+pPaAU=!P==l(%H4}-t<%d!etYp!cUFf7gMIMm<- zNkxeQosV`LU-nuWn-DJNdV0NC4YmY;KS-(JhIa-#BY9ZW8Cp?N0WP>-G}Cnl0Xyk= zvmZ#1DG+kpyStg-i>x$}z8J6SX?eXM4$bn4a8-+W->ywPnQloV?ewBOc25K`B`CO# zjq_stEZN#DTd6s6_`YkPe-eHO34+T3%^ayooB>unoLldUX<{ZK^EA%TXp4ve?m_vS zJ{-0ZI!J>2r${J?>eE_OFp@Bm(Dcoya2AtLs4X68*b@8_5&Ox4QW1}nv6}j|{_aeL zqmQY*%GynitoPnp%r}c-^wEC_^epDj!uowToH^-Vg}F3ta^?}8$}u%r;YE?36g79T z?gJELBw9Fsml%C>;|d&ArIue3wi1Dwroj~ayE95^C}KK)WN&je<`nt-xrtVoSm)f?;AJARF1P6=xrqoefLo(`OZ`&vseq?e`0dyv9H zjZlS?-}1Ovj!VExdwFXj7gX<)ORU8UYF8<0+n-aT7somBQ8x_{(we}RBp7ma(S@Zb ziI6;??tFkgT0yHw{ISRSi`2rZ_LGEY$Xnc1ybwUKC(PCBrsfv<4&5jd3qR2M{ob=J zl2>_Q)e6GZJv;CtdHH*cNbF3aSlcJ^7 z-`3r)qP3gIJE_PGUc)<6d~oe?JW}>LWU3cHX+E_jpPCRVzw+lsZtdwPsX|>dY(A%* z`L8xWNfiBoqUI-O)ZmV55o{OX&^Z7p!anNb`f~7=HoYLRa5et%SNAC;zG{mhLdwjt z09Qp35Qa{KtkXGu7x(sWar7 zB$Gz5vNB%hjUrxdyD*JwzgEgiAM=C?w%G{`nR4)+oX^ z%7K05Y6p12GE7Ebqnz}t_3Y{o9wgf6j?7EvAXEdmteEu+dtFbtl>JzptRyueUv4Ti zUq6gywbNLHFS*So3r$|UDYK3`8VjI{*0w%x#~MG0_d{@__dahSO@%R+E?q_2c;?SN zw0H8LW+6R&kv3s4#>&!?BxY^TeLZvpgV{IuhTWBfu^>{~g{OYC)0AFYV30jlI3}?y zp3KJXgQD4OveG>Ft|(pxW3BEy!&vMaq;kZW96zUvhhUJ+tE~pxbS?5_X{kt6#*^8T8LSu*PQw zY|sDfH@(iMh7rvF7&edS!CZ$2&a`~wr1zX^Lit57pVKc?cs+rlF{M$05$Z!#Z@&P? z%Qr#We}c!C{4Iq=zn*mxWVjPP;%pl{V1L1Grm03>Q|ms8k#u?4F~c)*ZKp3-FcoF< zo{a26>Iel(V-n(t+FymL7ZvT*$-&cXsC8&O$!hJc(-`2Nt}wSDY6c48(r$pt)OywD z*-HrzLVgBGp?>MeVNX*Z*Uv+&{c92GG`}@mQSxPt*a~|QUx=8#38nIMEs`gGF z)0Z+7nmZ&)Vubgf1wMzys10()?q|&mn>+lB?!GELek-8O1huBCy!O1V?XbPt-H|pd zB{pqDGvz=_p~~E;GxZg5-Oz6wlSyP2^g-TOLfaM#LR{U}o*5(6*YitX|&*ev`};U%_DYGb*{i1 z0BhuF{uLD`+;8m(1)PK64J`gnYbEXt?H}5l9?}0Gbv$(&wmO4MOr+#}jjX9dt-FWD z&w~}%Pb;U-++M^xMK1>N=#d}?PU&ybdx zEsu+_3o)U{OgesN{chbPbe*JHh7w9aAmv=U-Fn@je12R|C=Ru0F7GL*~SoR;;>qk3vSu-vq zwYBm{$Vf68rB@CIhXK$)lF)(uO^tFkpEk{u8HTn3OOnXQs+=BpcQ_ELIyUFlV_-We z#@4xE(}VA?Xer_GH$?z~NPE2Xy2$BIiB~unDWvv+*8KNd$QK-p(QfB+~25lAkYHP{lR4CM67`A47 zM>HBgST+2%FniQvVfhp=OMLmgBxkAVb+~rabn$YG{I;LkLfG0u9%cDzlnL#tLGoN&#@x_U^rv7eEqx^u6z8X;|}VJLKOf*uEZmtub4M zULtq8`PUupE(u*R(Yr;Y0;S=KS_mv@0P$D01>5A4V-xlXENK1>ti+Y}^ zZKj$rHWwI*2U^9v_*8vHnh=j&E|T>HtVV~2AF{PST@*8|oO>qnu&(YsB6?kk4ahw>r>K)N?=G|KUQTE_ zjaHP}`!3;L>NcO*^ZYvpJJ0j|Gp&{k!EAqj7fLm!<{wdte})3(V-n`)Cd)Qb%gyu4 zL)J6>gU)b(q8>4rj#Al0f#uY3BBC+BXV1p|n_Ues%Y<(h3W}ncM*W9@*Hw%@R5d1A zxz`0VYqRzGuK$B#V2pj-Do(zRw@+1b&cz(l8NR<6LNGHk&{^v5Y>%E?SqF-Q=1S<O{)oqfbTz!!Op@CWk=xr;JJYuAlJ0^D83uK zX6z@7#oIAYRUfm#qf_b^2FZser=(QdTv}EHygphlRVAKci*?Kio|f3%z^F@HLt~@2 z{q46i8wEWlq#XWUXsuo1kCw1Vqs2a$>zi>Qz^(bDyd5QXQksR>Dk&q$|U45bVy>BgkW-xQU>&+Z-ID{e)zBSHm@ZBQvpJk|dq#E~=VD#@Ek+)+ z@-&o_d-i0G{Q`$$;PUscBl+v$AFspvIy=wC-bU2S@*x6r7>DK{$TS*io!q!JZNN@^ zQZqJWS9P5vt(Nc27u>3`Mh3z97Am2^l>h~KC{35eO1+(&3kDYVnNClGa6iTUr7@~Y zcxs%t457qJU_w`F?CN2sgxv(B(;Ux&d=FGp-t~rz`0|1 zD@U2PWMvULl$K&@&YH3`t-ozzREGmqr@>mirWji^+z7>_RhV(2k;hC8?&_R6=vE~t zDsXW?Lk5ilj*vAE%q!-HjM*Jtd$~a-f{8CCjhzb&MA6QIIBeXuB02Bu-j6>T&OJBx z)jN`xm6qOzyyYqfl-Qz%_xHb)q!dNkE0 z9$MwE2GSvX{ULgWvQ8Zt*jl+av(6XKh2hiG=Fgs3%=Pu-%1n{E>g%hyCKm z#IWfY#y7&3tlo@FEZ+B^Xcl^-SP>&0;|2eMxvwLuY;FymL{i>H1npD4+rfwraV0ea ztBq!B1A9a_PoYHb0`9`@5^&ewGSv%g($&+--#X`1XCLPmGh;s?DtIn$u&{u-ljII|lg(VTBG_At+kD1$_yhg@^N z0=DSy@^xKI$}f~MeMN#s#AHa}HcpO8QG>L^ui#Fj>Jg(k*Nq0-7LsISaySZv`wCo& zxvb$dFhzBAp(w*gZ+QU-u=;Y|l zmBWaa8^wRFLF_RRu;=MceLImJbh2)~YQSr3Tx)2iG-c)*2|+emn|#3hUcP-zWa@W> zNhyz+JzQ3@cYKJ{q)XwHORH0(p;2p?7f0oab)!C3TgCCn82g%-ZJI6`!?G1XaV5Wo z3c7{%CsPHkqApQ30z#S3(x~_vQrY5OUIzKHv-{~s;vRBM7R`yqls!{^Yizo08%2eZ3lPoe?z3=mCAIeYeB0Rzh@%;4k z<%k^k2(r+T+QmO_R++?vqKnJH-^R$fJ6KGWh_)TDl)Y;dpdelDVZ(Mzy-Y2)sl=8Y z>zl1oCTBz}K>(+Mt2{W-%r{5QL)thGNQ@9pWJ=-x;TVRr%KIVmwx~s<#NP{b5W>}- zaqjB=uJyzrRwIVpcrRl9i|Y@SZj4)GqAJD*blAuX2G#&u?0wK zh}ZtBw-<~#YDG?GcS4*wih5M2n=lqS<*FUbA-+Hp`c&vV?}WU{g~@TR$)WUo)_qW$ z-^^>-c(4q}4s<=6Fb%r6$%(jL>2SyxF7hfn(1eok|FC)@6_j8En1DQzP9MFnMwEUU zr5#O3@d}hdbG2t4J~xFthbz;w#0P_+MmzT}@HT9j13o^QGao_M1#sf9N*nCEO2r6% z+c=U0YdN@W9ZGAS8;a3g@cyb?$ETl&i8z`w*rf+pnj@tLtx(^8PwlzZc$<9g_%VaoE`XR_S+YJFcI~ z+?vyewHaEiLg}lOjhP)4FDoA_KZ^hr zCp!l>3p)=B2Pc&p2QQViySuX>8=IGx7pu*G&~NmHW_5D4S_(gY69^#wk3^8Qhl8o0 zpp=uDhl7QqyP%-z8`KTJQS#c%_Wxl1N2j2mwS|q9wL5@AfD;?w8uo@E`Y$>E8>4Mw z?r!}b$kcCYlsCxx|AHvlI9Ry*I9mYz$0{~wM=P-!E#?15juPk%1>oQj;1*!#IT|*;765ih$>ajjqqixo|C-WNmj_td*jv1PKAVH1yS88l=qwCMPSY_7S@LM~Ltr|Ae(LzmEXcN=#7<0H{wu zc`%h zJb9vxj*Kgnl_IH%Efw`sHrf=|6*`H=%;oS1DL0^}Az+o%7=Rj>2QHxZuWV-pc(-3% z_+JPetR~l7;uX=5%EX8$Ttx(*MD9ESp}9n>AT}`G(X~HL-!*ZKQVYZq1?x%#y|9qS7Q`LOlQUv}wpQ**n~2ehO^Z9G zl7+>myd@rF09HEvi&Eb-kc-67@dJAip%YQCwoYb>?Jmc{Sx^cNVQ=$tC4GV?WhC!j zNpJ^C#mu)+e6SHoA5kAhAKDEnl^7?<@r$7GCjx*WydSD3I)S(a9oBh0430 z;B4|$_*X-15BzPqpE3ifE>ay>T?D&?o2KOPb3TsR=7A47pTUeZ&-SOH7@s%%p{ ztPrh)D_&l`*PvW`=do}#&uLMB1j?o1CQ76)UMn<%c!=X&NIn#^3d%pd*$oo%BGWWX zHAD9{e3Ya(m86xH2elF0OThu>DCiE!HuP5XEyeAxbBJCjkWR zP@x+STU;gX!UZx?*y8Q0*Ffd7?L2z}SX!{^+e`1vst&xUcJHd$a`~bdFU-YR{0A?v~0e?iL zovGJ!{7Q$|CYU<8yj}Yx@7;bRO#)eK24EivC<72XF$(=T@_mr2?w4`v_!*!kpl1db z^shG57mEj?4yLR1HGX&?=h6?rxn$|`W7FgQOVWvLGk1w0d!JaG>c6{nlMu$(o-Oo6 zhG6%3EgH0HUeH!q`y!D;N*`!z*xS!%kF%FN$&wKSKa&#}M+0Nm^x*m1);Y2`M_ zDHC9N;L$^3w=+H)_G*i2g;z$)0eNr7A5akR3stC39}_*d-*y-52t(^R#d4#Pc_bIc<_<~W zI_}lvMzC+NhpVe0w&)pJdzzb8(8@3{c`Oa_A!uw-!5}opa)}M6X`%b-1f&c?V;*sY zF~oUo{$c!pazNLWgQ%+N0RC(^*GPDhN*bX?2WA^F1ar&_5zTI0mI(e0fwEtw zZ}XIg=OtRfxo3)b%I(08Ijcrk2v?-9ZelH+KlzJNV7h|^nHSfS`_$~Q+e@9 zw%vFsP*~uHdP=rvOz`m{m$UVYIo86=yhOpox8;Dt&AjvYzfh9-co4)(tSMJfN+M6C zUU+a%>>;}c@5Ta^k*vcBgg+uYq9v_Mlb0!pgh{}OJ;s_G6TSx4AA$G%YmWyqZXlHo z&w?MpV-v(*94i3zkc@QywdaoRDc_$W(1wRz0E)~647p|aio#eaKV=SbUM?u+l&CHYuHv!evo5EZ96yu!b&5Zm!r71+WLof@5FH zy=n`@@f^9ihFJvPl+|7RyOXwsUQAs3Q;-~=9Uz9bp2ndwKo@oTJ)!s*@wka<^<#-B zUj}=ck_wp%oG7pAE-2Um~SlgL^^c(mv`7ts1QebE@?S}I??P`Ox3 zRS^WsL8wIO&oYM-H`SnBzl1<%Xi=Vd30F)4o=ERJZ51vAu^zg&eT;dib|;6|7-){KHTvpr4{mOFO>y|ZE&fgK#C><+P-qSv1Bf!BNV^*^8*{l0 z>(`A<@-_Qh)W%^|O{|XXN%$^R$v2LXbg|}@#`59_2-YSm<@fGeA(iXMQmm>-%|AQJ zX`HQr&csGdGS!Ge9u~|`;o;>qTB38~2UZ%MqMGkw(`05svcJY11dQ&$GFZZq#nXg5 z^2##4<5BvqGNqk@d+|hI(wy31(vpQ@nnuW!2$X}&gsU2nf&aAjQv?Fkq0PmB#^WI+ zl;m<<{n$hFA7bmi=m{y+F-*(AXVvcbtuLsb1QfSn_@)>Wq5n9~NR*Lf04u1^_W1E` zjDYJ@dGl-iF8<%%Y3)fEHk$ z53ZwzyPU}1!*Q0@rj^!Zq6IEtz*3@1{30HB5V}kE%||C!#@xINvnp=H{wb0K^$|kz zq{v7^+Do=g!fY`a?7j2?7P@~Z?RtqcxUXr(_q2xSwY0L5xSTMIz^Dgho^r}4HI-T~ z!PHh~PNC-`7oNt|Z_}*0M4&O^hkbz>DhZg9v?3~_wP_O4Z+SLv((gQ9|FQ(G2Hv5j z%3Bg_iKk$I4g;@V#O7NXCL@z2E4OzD>9lXvs^*&WpkOAhuU2jxKi$auIX{o$0wPGT%$ z`=%`mdwlR)A>Z?R_xlYC^^?y>WJh`e3yec2yzkc&=047>1z3O%$oyUlnK(@MvC?dn zm`12qdUj8wa7Vn*-ZD6T1R9W#=#B1-3j8xhmBqiLn7@!vgi(fSsl2och<8&4pg-Vu zv2_>3v#GJJNVdYYVp+rU0lY;nQ8p71=@OZx{LyYHPK&+Q>UL< zT`+};cCx@5cJ4zkpqkU6u}-7bnt<;w4*~pdeQ>p3B7(Vk$J*MR<^suwgCjTIctiC= zvev+4Q0c*_!Ge(^z0*A_U9lq#U;{A2qT3iYMJjnZv^Ke#h1&_Gt&CNf0I3XgO}Q)) znrbV-h&E`cK8vRuahT z&7l3Oa3^!jktjsp6P!&1)XYA<$QL&Hg@RL=JF-AWs2xoY42qf#L_y?L6jT@ZwazR# zEPhGPgrL^wti1UB>M#G=>uxLx@J-Qj?uY~N>%FfK$Z_by-%Q($J+$$;iiWP-(-Gg1 zAd*+FM(Pj*<(KqcbIK&Z=(O0!Qi7?eqIm~Iql*YvPLeq;$L9Q$BMOaVF*T*j&j8SG z&Y66>s8*DQu8D>hF;o@N+Dk)&@#?-q>L6C^#<>e1Yehc^eGkBVB`x9z zWPaO89=t1>DG-78BhXR)%!m4$XxCJOKIJeC)9dT|H^mKD7p{{S8&B{F@&g62_;h#C z>P3`CL9lrN{%%0;6B`bAK@#%NX)-~FD4y4wL?t6q=U6ZRyJ>+R49Dul>YY-3?9mi7OLhj`-c$^_HQ)cn5j> zRoqs7cu30@Zhoi|4oUxji|C5!{O)JZt%(viS$ zfM)X6OGZv#Ov;O|A~s*fbu#1)Hc82jTAc2<9JO^MO_4W5=*qL*Fkgp2j1=h|Sf37St#g^v6!Gf?lsb6)ROGBhze0m6dAU~_QdKNruT!G#EX?f3w zYyAo78zN7P3Sp>wN|AXWYI~O2d}M)MVR9*{&#`N&7r){0Jd7uVXIXM&H<9m&c}10F za4_X*1!)g|k-Mk-*vG4y?NHgQFWT#(BLHA5ApV1L5k9#oQ-Trcf1-Qs?iB-g^9zVI z1Qjv2BAtxC{OTj&>rdL6>~yS*f{Di|vx4eLA7L_l-s&K)b9FH#jzt*l|m1P&OPhSjrrzi&U5#|P%=lJgVCsRoFtKn;Ln@^wYx~qnTL>P z6clG<80Vh*DweCD9M^2sNs1Yau0aUu zp7nxRha~WD%qG{5iN^sh)Nj?P#yPq+h`h#Lmmmrg2Wj!$+JWsVTq~8j>`lEOG2`vS z(2Z;GJnBdp#@44$2HHP|&Vfo(+?ww|dHivjUQcSB_$G~$`70lFaIK$tjpO2RhdoIy zZyttx3>X;9UGUUNKUp!N_NXAF$MH?7ijpn#F3jJOzoG6VsQw^Cg!kHZ=%4HGHt>zxs}dyu@^zSMyh# z*F|yr@@QAeGebrlK5Fg)84FW^`Te1jULcXHwq4 zgU{7Hi+x7uNLqpyu;MoAZwLTKYx9#V+A8b{F0eb?ougnY@4WxyW%7RgQ5Pc~yX~8y zo)^i1)J|KV^HY7%MO@HNX}(Ayvvg=E8z7;0*h@GXX~>s)^K@d?P2{VQdZdJh1yz^kpQR$5+*SEk&sEr{ z^5xTxI|yk%G*f)f)o(a_+rt#y8OIZ%(5UWu9QV95phzVa0WNQB(yezkb=9(SS)csh zLwxL|UkYTzK5T9mm+G;lmiE9=LWy{I20oExxh6f~2q2Y$)zi9yB&LYRmO>H)deZZ}y56-lklzC)E1iv&@wsJ=~l7 zd*b`;WtQj~t6aAP2zW9Hq)!Wk&St!QgH2tABS^8vE1CBE%T8lR*8p?$Y%v{BFAltJ z%+fVca12^SigjE$!q=E5nsHXWXFGeKG*A#h!?XK+ zC1hOP;GON307J36PmN-nt}7aOu9uxT&Yp^}YQ)526q*=kORtFG;t_YZVG{)w^<{9J zKAg@D(1lA$Qb5RkzUIs~?*+mw5l!P2Gmq?H#{|`X+CbuVSZC1U6bU;^ydymgdZz-> zCuctXy&!vRdhAWI%HRugZg?sl%OOA8bLTaMUMwHkTYMV-%#E>iYwmvnAMdc)v`!7Z zL~I^{IVQ0v22+IVCKjsJuddd}#;yO`5x2VFb~PtQTuV9SHCn6!On=5$XHAlEBIB&) z3cgu%X|b>yv3eG#Xgb5ksf9iNxs_Y=7Xs_@u)n8^!=UJLohu=e}OavnHCsodi;v^M?is7fa2JW7)}Xx&A5thr0d3+#%6*O`?3D|#+Q2}xtNQ}|8sCB?83?q*wZIp2dpmUX}h7N28}PJR)M z`?$9VFYkTu_t@;@t>TG2yvHTT_}9{8RF=t5k=5VNoq3?rtVE7;~+DRU}+!GytFdD@vP{2qnV-FL)v?=z}`lCchmc{Fugl|}1 zsCIYZs7pPbX@%+^Ac^y;TU724@ekEdU~qOlc=NF4YeMP1p+6rRZv&54iO>c9Zewh& z$7-~G$^Kj~LYbUxY*cO0*42FyR(O3bl|5!T(&OMnJv3J?dW7Fb!sDa#2$jh#v3 zyClWS!!hwfIF`O)jp=MS7pdS5e@xvw7fHH5rpUTi&e*=1|0vA^=_MK5Y_q7p|00q< zk8PxJIPy*CsRk`AB@>qhd=Fkag@(IJ_-0^BMy34ZVU#-hH8?-E3#>s+mz-%n7m>x% z+1b?DJdZUK3vBWU>I6}4yb&xK*x19UV*V@d`DY3C4?!$Pu9+_FfJYP0xWmds_}$)X z*AApq;QFeS^5i^I+TFVKY)*wEwiD zkeLr2f{X=vPfhXVI^Ux^@L#i$ah?nH7Gy`lj)_d^;&pg>RF!>a6vAIm7c@1Ly}h}e z@HbROPo7}G-$`_-GI;%-c;#|R_qJ|sx!%@xBV><1@3x_{4@*>^D@_WIm(XDS{&ZqR z>MT=+TRBdz;46(m)U#Ii>jJtM4ELp51TY&V#8ImKS{cl2CczUg$|3LNv=e?}16iz_ z@sQj-O2pyi*@b1UMAFi4ss^<^tf3u93jh1P;^%9_^54pr_h^Fs_{H}wX1HgjxPUZd zd}dYXmUrhU^u^)f*`~%})yqCrPb&d!{1r1pxOk@^GVk62(_M^+Hg`myZQ4h|%CS!J zUj3Fps>;+@vX_HPl{iKOKBBAmcDSM-%8( z$Q}<~;0~q2KaX|e)L-!Rzf2lk@N_!;a{oC(b~h~=D`^I&fVQDc%Afy@Qhn*OYum5i zCwk0nym+8k(-Vn{K0>i}Z++W<45+)J!Tso8gudT{RGZLBxM3I811NrB(@Fh2_G$0H zxW9X-eZojqbpt3kaZFV-pE5R0_vS(~v_MzgRz7D^?Sqz8=I%ah=$IcGP27G3N4^g- z#gkVby82R!Q)pug_9uRlLhu-YkDK*dzgQ-;!ZTZAFOK^rFXuXuOib*7i>#u2p|?oA%0@Y3)+ z{KC(_XsZ0@ilv84on0aVhhssrO=X7aD(PbFXa^(m=m3T(Tz$|C(9jo;VqVUsRBSC(zum%aINH zra_I#PZ#%x-#8oZ8d!xqr6i|xGMfo~kE|d4XTeU>grC&$CL+9Ka)- zdhv004jW?Au!jsf^&Z?~ZNcF%ZK8|prKD&;SsoW~p=L#LuF~6j)eM<1y z(u4L;@zydWH3xLCa-(XSXoW7+tH!9Q38Oa0eZ%Mu$SCrBC73#X{;oYCY}ftwS+bSb z6GR^NHr^%~@W)lJcP&eYqJg)9&JNWT)05kJ72~wrp{<#X_-GAyR^@4Y>h(A{Fn-IT z`18u8Oz79=oADR(Q@DLsg^B%|3eSL@#|s-onX$MG`Aw**xr<7A5`!+@0eLQ z|G+2YC=wFS+%GQXwsHG^02N6X^V3^33z8mb#yd$sfWbyKv9I+YW(#Ve+^ z&aRY%An>?XIgvPSW^n~<1WCZ)uCW&2mF zPC*u+tEIXjH)OPV{KpSX&KD(cs|DC2xOdY;^9(m>ye>Xjt&Y7JYo*I}$LV(=rpYjy z>E6?0%03krxk)I@HyTfJ!YDlKQ7?dLl02LoP(tW{!VOS-Y`u|jVReJz=&*CI=h)@G zH!P^-L57>O#ZGg`6=qxXp?#;`ZQ0PA9LVjajd+%E0|oCg|1h)XWc6yh6ZR!#Sr@RM z6XFnlB31HzU%$BcYtfL8oum`hKaS^v`JxdjY3je@x>JIWUlApZVwxPl+*fLw60A~> zGK_-Ua3e)oJWT*k*Nj^X!%J4bl`Efgb$o0i@<{#DYsJ3B`Gcx4K|1djh*JlIG^#jN zj29rgNOvtx*pQ)ANr$LG-zW18dn{pj%9a5qoA9c99<;4vYx{B#RrXjT8NcV{&-&?U zSHW6LTGiiw0UKgogkQ232hL#8MHvb2>cjsk(LNGv?4Z2eA7IFbwp3;|-b;cgB8}G;dr*bMW zP^CssmZ9vVzKyVOq-0TRj>t=VD*;td&KrDUcFfPnL7kkKkS$cdPnT7}sV)p06*!)R+KbGI5c7f1xf zNo8gSxQ@aqwFs!!8(TD%{jMnOD*F2e!bi=1Q-<4w%m`$UEwTLAA%0a*;tBTLR2iEY zgnY(EDlIMLg~_Db6swQJ$9c`}%ytQr6%`7Stxpj3i|R3&=$rW@dA~j}*;&->?4xNr zWo#~(Yh0fwEQQ|DWG$n{@zo-^QDedN`-N8{H&=2-zLlxzPha64yi8=&q9-A{EI9{` z4yYq0Qlvrc~2utC0x&MBq!DWZxOY)hIjVDAB&9^;z?I+*NO4{JcM%&LUQI1II zOy{C%j)2uZEwx9}|8(rV^P`E>CCk28W|0k;YE?4hU3Sqbsb(iEH|Ebar*1K(qPLA) zZcI1(%+;^s9X}7^XFgk#vUNqdiSim69$uj2z<5F4HB^nijYGBP|LQg?9w$W!lGRE? z>|?h3?Tn-m4WmI}jwM9C{pBDH4;+ytn;}ZE`G`J4&LOJ5Nm>7@pdKVB5kf_EloyZA z-9gDCahPlL&fW65@Sf}V^33z6`}LWow&T2g0mi|YkFeZ&&2Ua_Mh!3dag}}N2-eGB zB_{0#CAQS+)3?0BHp-zdYXaZx9Vqx5M<@1NDo2UM9+?l#wBu2K8LkB%@XDJTG!hyq zl1hl#bs6&fO2dv!p%}oFE7(`D|D2Wt9jiEr9VabHTfh$g757AfSz|FsloOlJ^fJ9@ zj!V}_Q_8F)`Y4R!3#lWifkE!asM{2&(h{g^8BU*jy;-4?2)ezAyw1FPo-r7`9&^;3 z#HV%?rk#(4Kb?c9dCv9-6#x9ZniswX&RTJDDZF2QRs^y!pDfGiDG)_T2G`fur{-oN z_+cjrh{0R+@9{TvJ{}0kn`>I2V$C9cvr~LiqHR;n3X~KB0i^}+!i(#59W8%^4~YMi zWS3*aW+Hz>9H}cpL&T4)Q%|JL_^y$xSj_P#*_f3DqKyiB5F>|9C zyP$ZtvIa zHm3Vyc(SmqKB{erkD8jAZr8OKc>@UfQXDh>j9=Egn;DOtsh?9;${)@4QyYkJh)sk= zH@9;JV8cQ}WY3x0E3+w94UjS)qEy9X3M3Z$gj+7U7&HP$o=dr#PPK<3N~rykbxhmD zrAnAhl#%&Oc{sUA)xbbWPo1OQ8f{2>Ru*85<=GSYQcJ1NvRUv1JHlc!-nSEQZ55C< z9KMInXA13JD0}kZ0*Eefwh&Av&s3=PTGvRaaQm4w%NPgb(qDAOQ*1)}jP07)*49?W zel%ea7QDgJ%GzdOkdkn-J;5@;k^a?M@lJ%10(Nkn$bEL)2s(IiC=?3o6P%^lbU9hf zz#$Q7Ni#M4W?^hp9oY&=3EY;TBy*iMVN}9TsOup%L*eW)YF!CV!a{Cc2}Z(SrPT6O z)bgfrI|`k@VwSULxuzri9NklN8pETV;38R!`^eGe3t3taU(iRG^(M7ISPcpWM;MU;yfkQZ;a|u$1Y>ekl>Er2RjvRuR5dB+{4f`%N7OCXSlM zkPstW5A(>+NHL z-g+t81^B&QDrg|t?2oYOl z!8guq+#_Ot)hDI}PRr55N6qJuI)4*Om&4j?ipxrk#tJ#X$0Q@tT8hTccNPK*NlCg(=Y+2_?(Xb)QK%YK34&4mZe zspTx=P(wStzgqnKQ1m%d7hrW6j5w2>rs7LE~#y(dt405$p zt#ZYvBz*SqC0`2bVQxXK5>u*`H$VRokv~D8y*&x}@6%!yLN~-cxlws0|k^|S##q#UD$%}%MzgG zB5E=^!a`4*#zZsCPkiy7t_6}8urmOW9F`Dy4`XCuy17#J|2fXQD!12+p}rOFX}t~n zuykq8CI-c`hRYtXe?Vh%I-EwglaPU&`sYalyFghRr!|6mjvm7TbfvHPOe5O$3|>M{ zKeu5MU_`X{98!!>e&X&-3v=|dq^sY$E$Vqn0+fl_W7gI9meV894L>0(Bzhd0Las-3B`#cx|C+biBq*Q6FuBfI4q za|)8Xu8UQH#p#P0T3Rk!=WDA@J8`Go*J@Ah@s8-ieF-u~#{53lnL2^XDnK&(whWQO z$H4RWJJg6=u)(5TxG;DFHM2~R<{ks>!=d^NFLX-vV5%^?p?p-|oO;CrlaE=5RLMhz z?dDt8J-RYqPJApfU)f2se)QOvLd&sODuH3*@dLw}M^-?~XaO*18emA5rh0llVcf-8 zth2C!IM~sI8$JM^jZY_i_pHtJwl+TX}d86UKBFQ*Ah)pr9c5zUpe; z@Xe)-SliGK7%+7MrSA-xK6L$Rv7fM#i9E5N26-G9mxSI^+X`R#8{fEw%XyCKM8oaxX@K=aMu_j zMl2NYgnhiE0mTAXh^6TV^^3Ssw@^#N29r`Jmk^dX`&TueUHl=mym+-O>-R)Xal-tU zX$6xl>vbh7J)R*5;|P1InpXVe(jp1OIkZ8!$#dq2v$pevy-h#Oj=P`hq9?8P-aitV zXQGQr+4VD*t6(PRYw5w`M}H)tfq(JWY}-5Ni9`+}GhzKT^o@!7zN2NBv&(sO=IPUC zbJYkSk>A@q5zYtH7R3PntN^_+>2CZKDSxV^idXSRs}Aynzio+qDC*10x|b+<2|wY| zu9v`7&hGlgm|FmDlSeMQx6{hSs!%`C{K)uQ47ABvN!v8I-}DfAt$!-}YWuLPlmnD( zeL<*jBACcq%`jxxTMCPY4J*77*qVhZ#tuK?r>EJVhqhkM8CLt<%)8N%@MvjJti9eIcvbq;41_r>vYio?cKzHGM2tBTQ zsWjyrDk=t9*PQ#_>JqkXNh>YXj(7L>UQ!uhmP@|P-==3npYSUqH=l(+)Cww@cyh!8 z_x!<{eNu6yz@%B!o3>xcBVYH^Gsl_!so}W_Fc1<3b6c2`vAUjAxBNC_SHK%FILjrF zi7hA7hJgDL$gs%xrXz|z{87o;z`-R)18rH;Wc-QW{>C< z!`0a2^fQY}CeAL5BL3xpRlrXLn-)ccxMvoyh?-qMGpXOV>%as2{fe4+YjE=yA^?&} z0wR&UGTov8E1~FL=pXp+cDP(7sC=PST`~CL$2d{*m@&9Q+)0Esl&YplS;ZnNJuB}C zQpK~9#jvQ5ZY(TR)4`656De{s;1*tJHdY%UMf_YC5%ZMh+|l4*n83;L@!Qq1Z7oR! zdWwg;2Iqjdl4!U($7dzpEZkW$O0#T@^XMUlqTVt1`h#(psvF<7n$!hDBjw%)O(B|! zK9hQ@D+lf$Vux(vVVL5%hys$Ws9Thq`YDE07B+%Z-|9Pbs@#ApA-b^nfWdJ!spytD zeEjI0%9I#I8}9J5pc!{f|(Deezn~I{F3+ z>=Vh|8_oUKhmJ+b%0FMjjhUv}DZTK`CS!{cLrgn-ze3{}mj=S2ekwK()rab!?I#$k z+pafEq{bqwKbTTVPOI)5k z$O&ca0QOOwt-;vUU|u(EI)oaqpkG;wxVUn=+TBv zC{~ZH$D{vizWOReNe12aNiPbxbZXV}r%Ceucz|bz$gP##nC=SqTZzLf-uQ(h~fAlfZJd5 zjpM2^QhV0SeD4_8pLEOkkRUv~HF(7?#WHNk2`_K$*Dg%rMR^~)qB3n@Zy%bw6sFOA z&K62HB^HJebM~tBXCE!91qRoxesTM`42&VUSeb~$#80RM2K5yc@7=@`%or@)4rcFM ztmi$ToD20glVsOMmyxne+}(T}+RUiW%^IGE*1+b4aXk31{X`OW+C@Zp}nm3-hB_| z)@k%uirMtls}g{vzvc3B)`v%~zXF^8HkRnQx7d}TCY<)}ijyBl?GMKu!+_r_>EG42 zRGYL8N}rHA;VuJ_G)cAhjDmV({=9ByQ6U>HrsACY2yU&VRm_apP zUAzubIQ2Jp`q{E1Q0*5Ma*9FNs2hX*dUeJpNl_F-WUMigGiW?(C=d9m;aiHj2 z{Amdps$Mmid97f1Fw}0*kiChCO8>@e?)hV%{5e^skIACRs>76-zWY6eD@AYG(oS)L znNf|14NW_Wmd8Q;&mFDD1znQBvW zlj4oTh_Z&IJ@%FM&b%ak>>{IMh@gpDb%yBw1*naLi_dK7a~B>O7N{nXrrby_#>GW) zn)>CLtY?Jno5j`Q9;Pfu_K!pRXzr1-T26)OldCwPzy)KMG`!Xl&{D_S!)a-1*6No$ zHM#I;_$l_cT^LN1iPN!+pNyL1kc8CrIRyLx#QjUkcL>Fc<1Am z$=`TT+F$FsYizr`=`5Kfp0JTQPxdZUs&Rdi1P)8Tb-r(=;qv<`YmOvRguU>!*>z}H zy7iJR#vwBngY~ty2?la^m(jbx=z%|r#JVIB7L6ZHDtQxh&I%A6))nka>JO`!nAER- z9Xjdyy+>hH=5U)Y3@jLRG+(3U6($w;)Am+EdbTSvUprfzt=vEBI46;>1j%U%joLqy z; zlc0?q5_CQ`L}H<2&7-BAm*V}NhSe549o4(@wmvhBL@Or1jzJLzIRX-mV8A+oY!Z*Y ztC|hqZ{(Fo0X6(;3pDpMv&PKhlS&5t-K0mg;7|3ixb^hgHFdsN9t8Qs$trdhy)m>5 zY|QLePWBF}ma?O`lK}6uBe_PfbEf33?JpM3j}DtGvOUX#cf25!k@aiM?t7HKQk7Cb zw83of8ut16RK&}WwhP66dKw@6OPOyX?~mFzA$OC1NwRu;R&~9nwDW#TQC(GMCei6lT_i>57n>88^)+o|fCrNXBo=UKaOl<HlhQb+mNzFmbT}$l04%Sty!VeK)fu=Vs<%=4Ij|XJ=*OWMbuFVq+&)W#cBdc5`#$ zXJPU1@L>M_ANqqn(9Di5R;%G>9}EEm|8dl?cDFa>=a+OebGNr}aO3A!`GC3t*vj5J zSpF}}|E`mt-`e84m9-myjgK7z;1c$M!T%q8{y&WNcXK!E{~$9}6o?;?PyYj=_}$*Z z&CAIG@V{Hd;^bf@@>@&k|Kg*l@qq%caq)5Tv9fb;vmd18GJilY{s$lR@7@*wR&nu^ zBH`1IEUo{MrKu(du>5Xk@zH%2dj~f=M=KUflONyB935O){(r%+@NjdmbDEp+m~onz vSXyxMS+MePauN)r literal 0 HcmV?d00001 diff --git a/apple-icon-120x120.png b/apple-icon-120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1189d39f7c34ebf35faa902d91b7b23f0662b0 GIT binary patch literal 15322 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 literal 0 HcmV?d00001 diff --git a/apple-icon-144x144.png b/apple-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..93ee8cb09a215fd8dfdf0976d4672dc5abd35651 GIT binary patch literal 19676 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 FzX9@)T8{t# literal 0 HcmV?d00001 diff --git a/apple-icon-152x152.png b/apple-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..22cadc3dba61a59aa551bc2a4a029d48fd445241 GIT binary patch literal 21264 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 literal 0 HcmV?d00001 diff --git a/apple-icon-180x180.png b/apple-icon-180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..99e31982283136ffc398e1d4816d024c1f2dd802 GIT binary patch literal 26748 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 literal 0 HcmV?d00001 diff --git a/apple-icon-72x72.png b/apple-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..66a15d8307245d32954810c754304f31e434ffbd GIT binary patch literal 7366 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 HY-9fmA@zu| literal 0 HcmV?d00001 diff --git a/apple-icon-76x76.png b/apple-icon-76x76.png new file mode 100644 index 0000000000000000000000000000000000000000..516d9eed3b10d630ace7c2b09083fc43f671a9e1 GIT binary patch literal 7879 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 literal 0 HcmV?d00001 diff --git a/apple-icon-precomposed.png b/apple-icon-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..6214e2e61f3679cefbfdd15864bb9cce32b32ef6 GIT binary patch literal 28366 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 +z%zct7Am(TH|l?yC4O1SFZr@#O92v8bc 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 +z%zct7Am(TH|l?yC4O1SFZr@#O92v8bc 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[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#3eaf7c}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}#nprogress{pointer-events:none}#nprogress .bar{background:#3eaf7c;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #3eaf7c,0 0 5px #3eaf7c;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#3eaf7c transparent transparent #3eaf7c;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.go-to-top[data-v-5fd4ef0c]{cursor:pointer;position:fixed;bottom:2rem;right:2.5rem;width:2rem;color:#3eaf7c;z-index:1}.go-to-top[data-v-5fd4ef0c]:hover{color:#72cda4}@media (max-width:959px){.go-to-top[data-v-5fd4ef0c]{display:none}}.fade-enter-active[data-v-5fd4ef0c],.fade-leave-active[data-v-5fd4ef0c]{transition:opacity .3s}.fade-enter[data-v-5fd4ef0c],.fade-leave-to[data-v-5fd4ef0c]{opacity:0}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#3eaf7c;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #389d70}.home .hero .action-button:hover{background-color:#4abf8a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.algolia-search-wrapper>span{vertical-align:middle}.algolia-search-wrapper .algolia-autocomplete{line-height:normal}.algolia-search-wrapper .algolia-autocomplete .ds-dropdown-menu{background-color:#fff;border:1px solid #999;border-radius:4px;font-size:16px;margin:6px 0 0;padding:4px;text-align:left}.algolia-search-wrapper .algolia-autocomplete .ds-dropdown-menu:before{border-color:#999}.algolia-search-wrapper .algolia-autocomplete .ds-dropdown-menu [class*=ds-dataset-]{border:none;padding:0}.algolia-search-wrapper .algolia-autocomplete .ds-dropdown-menu .ds-suggestions{margin-top:0}.algolia-search-wrapper .algolia-autocomplete .ds-dropdown-menu .ds-suggestion{border-bottom:1px solid #eaecef}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion--highlight{color:#2c815b}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion{border-color:#eaecef;padding:0}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--category-header{padding:5px 10px;margin-top:0;background:#3eaf7c;color:#fff;font-weight:600}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight{background:hsla(0,0%,100%,.6)}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--wrapper{padding:0}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--title{font-weight:600;margin-bottom:0;color:#2c3e50}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column{vertical-align:top;padding:5px 7px 5px 5px;border-color:#eaecef;background:#f1f3f5}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column:after{display:none}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column-text{color:#555}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-footer{border-color:#eaecef}.algolia-search-wrapper .algolia-autocomplete .ds-cursor .algolia-docsearch-suggestion--content{background-color:#e7edf3!important;color:#2c3e50}@media (min-width:719px){.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column{float:none;width:150px;min-width:150px;display:table-cell}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content{float:none;display:table-cell;width:100%;vertical-align:top}.algolia-search-wrapper .algolia-autocomplete .algolia-docsearch-suggestion .ds-dropdown-menu{min-width:515px!important}}@media (max-width:719px){.algolia-search-wrapper .ds-dropdown-menu{min-width:calc(100vw - 4rem)!important;max-width:calc(100vw - 4rem)!important}.algolia-search-wrapper .algolia-docsearch-suggestion--wrapper{padding:5px 7px 5px 5px!important}.algolia-search-wrapper .algolia-docsearch-suggestion--subcategory-column{padding:0!important;background:#fff!important}.algolia-search-wrapper .algolia-docsearch-suggestion--subcategory-column-text:after{content:" > ";font-size:10px;line-height:14.4px;display:inline-block;width:5px;margin:-3px 3px 0;vertical-align:middle}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#3eaf7c}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#3eaf7c}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #3eaf7c;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-heading.clickable:hover{color:#3eaf7c}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#3eaf7c}a.sidebar-link.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983}.searchbox{display:inline-block;position:relative;width:200px;height:32px!important;white-space:nowrap;box-sizing:border-box;visibility:visible!important}.searchbox .algolia-autocomplete{display:block;width:100%;height:100%}.searchbox__wrapper{width:100%;height:100%;z-index:999;position:relative}.searchbox__input{display:inline-block;box-sizing:border-box;transition:box-shadow .4s ease,background .4s ease;border:0;border-radius:16px;box-shadow:inset 0 0 0 1px #ccc;background:#fff!important;padding:0 26px 0 32px;width:100%;height:100%;vertical-align:middle;white-space:normal;font-size:12px;-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbox__input::-webkit-search-cancel-button,.searchbox__input::-webkit-search-decoration,.searchbox__input::-webkit-search-results-button,.searchbox__input::-webkit-search-results-decoration{display:none}.searchbox__input:hover{box-shadow:inset 0 0 0 1px #b3b3b3}.searchbox__input:active,.searchbox__input:focus{outline:0;box-shadow:inset 0 0 0 1px #aaa;background:#fff}.searchbox__input:-ms-input-placeholder{color:#aaa}.searchbox__input::-moz-placeholder{color:#aaa}.searchbox__input::placeholder{color:#aaa}.searchbox__submit{position:absolute;top:0;margin:0;border:0;border-radius:16px 0 0 16px;background-color:rgba(69,142,225,0);padding:0;width:32px;height:100%;vertical-align:middle;text-align:center;font-size:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;right:inherit;left:0}.searchbox__submit:before{display:inline-block;margin-right:-4px;height:100%;vertical-align:middle;content:""}.searchbox__submit:active,.searchbox__submit:hover{cursor:pointer}.searchbox__submit:focus{outline:0}.searchbox__submit svg{width:14px;height:14px;vertical-align:middle;fill:#6d7e96}.searchbox__reset{display:block;position:absolute;top:8px;right:8px;margin:0;border:0;background:none;cursor:pointer;padding:0;font-size:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;fill:rgba(0,0,0,.5)}.searchbox__reset.hide{display:none}.searchbox__reset:focus{outline:0}.searchbox__reset svg{display:block;margin:4px;width:8px;height:8px}.searchbox__input:valid~.searchbox__reset{display:block;-webkit-animation-name:sbx-reset-in;animation-name:sbx-reset-in;-webkit-animation-duration:.15s;animation-duration:.15s}@-webkit-keyframes sbx-reset-in{0%{transform:translate3d(-20%,0,0);opacity:0}to{transform:none;opacity:1}}@keyframes sbx-reset-in{0%{transform:translate3d(-20%,0,0);opacity:0}to{transform:none;opacity:1}}.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu{right:0!important;left:inherit!important}.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu:before{right:48px}.algolia-autocomplete.algolia-autocomplete-left .ds-dropdown-menu{left:0!important;right:inherit!important}.algolia-autocomplete.algolia-autocomplete-left .ds-dropdown-menu:before{left:48px}.algolia-autocomplete .ds-dropdown-menu{top:-6px;border-radius:4px;margin:6px 0 0;padding:0;text-align:left;height:auto;position:relative;background:transparent;border:none;z-index:999;max-width:600px;min-width:500px;box-shadow:0 1px 0 0 rgba(0,0,0,.2),0 2px 3px 0 rgba(0,0,0,.1)}.algolia-autocomplete .ds-dropdown-menu:before{display:block;position:absolute;content:"";width:14px;height:14px;background:#fff;z-index:1000;top:-7px;border-top:1px solid #d9d9d9;border-right:1px solid #d9d9d9;transform:rotate(-45deg);border-radius:2px}.algolia-autocomplete .ds-dropdown-menu .ds-suggestions{position:relative;z-index:1000;margin-top:8px}.algolia-autocomplete .ds-dropdown-menu .ds-suggestions a:hover{text-decoration:none}.algolia-autocomplete .ds-dropdown-menu .ds-suggestion{cursor:pointer}.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion.suggestion-layout-simple,.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion:not(.suggestion-layout-simple) .algolia-docsearch-suggestion--content{background-color:rgba(69,142,225,.05)}.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-]{position:relative;border:1px solid #d9d9d9;background:#fff;border-radius:4px;overflow:auto;padding:0 8px 8px}.algolia-autocomplete .ds-dropdown-menu *{box-sizing:border-box}.algolia-autocomplete .algolia-docsearch-suggestion{display:block;position:relative;padding:0 8px;background:#fff;color:#02060c;overflow:hidden}.algolia-autocomplete .algolia-docsearch-suggestion--highlight{color:#174d8c;background:rgba(143,187,237,.1);padding:.1em .05em}.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl0 .algolia-docsearch-suggestion--highlight,.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl1 .algolia-docsearch-suggestion--highlight,.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight{padding:0 0 1px;background:inherit;box-shadow:inset 0 -2px 0 0 rgba(69,142,225,.8);color:inherit}.algolia-autocomplete .algolia-docsearch-suggestion--content{display:block;float:right;width:70%;position:relative;padding:5.33333px 0 5.33333px 10.66667px;cursor:pointer}.algolia-autocomplete .algolia-docsearch-suggestion--content:before{content:"";position:absolute;display:block;top:0;height:100%;width:1px;background:#ddd;left:-1px}.algolia-autocomplete .algolia-docsearch-suggestion--category-header{position:relative;border-bottom:1px solid #ddd;display:none;margin-top:8px;padding:4px 0;font-size:1em;color:#33363d}.algolia-autocomplete .algolia-docsearch-suggestion--wrapper{width:100%;float:left;padding:8px 0 0}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column{float:left;width:30%;text-align:right;position:relative;padding:5.33333px 10.66667px;color:#a4a7ae;font-size:.9em;word-wrap:break-word}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column:before{content:"";position:absolute;display:block;top:0;height:100%;width:1px;background:#ddd;right:0}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-inline{display:none}.algolia-autocomplete .algolia-docsearch-suggestion--title{margin-bottom:4px;color:#02060c;font-size:.9em;font-weight:700}.algolia-autocomplete .algolia-docsearch-suggestion--text{display:block;line-height:1.2em;font-size:.85em;color:#63676d}.algolia-autocomplete .algolia-docsearch-suggestion--no-results{width:100%;padding:8px 0;text-align:center;font-size:1.2em}.algolia-autocomplete .algolia-docsearch-suggestion--no-results:before{display:none}.algolia-autocomplete .algolia-docsearch-suggestion code{padding:1px 5px;font-size:90%;border:none;color:#222;background-color:#ebebeb;border-radius:3px;font-family:Menlo,Monaco,Consolas,Courier New,monospace}.algolia-autocomplete .algolia-docsearch-suggestion code .algolia-docsearch-suggestion--highlight{background:none}.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--category-header,.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary{display:block}@media (min-width:768px){.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column{display:block}}@media (max-width:768px){.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column{display:inline-block;width:auto;float:left;padding:0;color:#02060c;font-size:.9em;font-weight:700;text-align:left;opacity:.5}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column:before{display:none}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column:after{content:"|"}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content{display:inline-block;width:auto;text-align:left;float:left;padding:0}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content:before{display:none}}.algolia-autocomplete .suggestion-layout-simple.algolia-docsearch-suggestion{border-bottom:1px solid #eee;padding:8px;margin:0}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--content{width:100%;padding:0}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--content:before{display:none}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header{margin:0;padding:0;display:block;width:100%;border:none}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl0,.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl1{opacity:.6;font-size:.85em}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl1:before{background-image:url('data:image/svg+xml;utf8,');content:"";width:10px;height:10px;display:inline-block}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--wrapper{width:100%;float:left;margin:0;padding:0}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--duplicate-content,.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--subcategory-inline{display:none!important}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--title{margin:0;color:#458ee1;font-size:.9em;font-weight:400}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--title:before{content:"#";font-weight:700;color:#458ee1;display:inline-block}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--text{margin:4px 0 0;display:block;line-height:1.4em;padding:5.33333px 8px;background:#f8f8f8;font-size:.85em;opacity:.8}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight{color:#3f4145;font-weight:700;box-shadow:none}.algolia-autocomplete .algolia-docsearch-footer{width:134px;height:20px;z-index:2000;margin-top:10.66667px;float:right;font-size:0;line-height:0}.algolia-autocomplete .algolia-docsearch-footer--logo{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='168' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M78.988.938h16.594a2.968 2.968 0 012.966 2.966V20.5a2.967 2.967 0 01-2.966 2.964H78.988a2.967 2.967 0 01-2.966-2.964V3.897A2.961 2.961 0 0178.988.938zm41.937 17.866c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 00-1.574-.199 5.7 5.7 0 00-.897.069 2.699 2.699 0 00-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 01-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 01-1.471-.636 3.085 3.085 0 01-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 011.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 011.82-.185 8.404 8.404 0 011.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 00-.384-.73 1.784 1.784 0 00-.724-.493 3.164 3.164 0 00-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 00-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 012.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 00-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 00-.814.24 1.46 1.46 0 00-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 01.233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 01-1.471-.635 3.085 3.085 0 01-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 012.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 00-.109-.875 1.873 1.873 0 00-.384-.731 1.784 1.784 0 00-.724-.492 3.165 3.165 0 00-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 00-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 012.073-.177zm-8.034-1.271a1.626 1.626 0 01-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 01-1.128 1.906 4.986 4.986 0 01-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 01-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 01-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 011.15-1.892 5.133 5.133 0 011.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 011.753 1.216 5.644 5.644 0 011.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 00-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 01-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 01-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 012.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17z' fill='%235468FF'/%3E%3Cpath d='M6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 00-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 01-.582-.271 13.67 13.67 0 01-.55-.287 4.275 4.275 0 01-.567-.351 6.92 6.92 0 01-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 01-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 00-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 00-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 00-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 01-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z' fill='%235D6494'/%3E%3Cpath d='M89.632 5.967v-.772a.978.978 0 00-.978-.977h-2.28a.978.978 0 00-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 011.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 00-1.382 0l-.465.465a.973.973 0 000 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 00-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 01-4.49-4.482 4.488 4.488 0 014.49-4.482 4.488 4.488 0 014.489 4.482 4.484 4.484 0 01-4.49 4.482m0-10.85a6.363 6.363 0 100 12.729 6.37 6.37 0 006.372-6.368 6.358 6.358 0 00-6.371-6.36' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E");background-repeat:no-repeat;background-position:50%;background-size:100%;overflow:hidden;text-indent:-9000px;padding:0!important;width:100%;height:100%;display:block} \ No newline at end of file diff --git a/assets/img/search.83621669.svg b/assets/img/search.83621669.svg new file mode 100644 index 000000000..03d83913e --- /dev/null +++ b/assets/img/search.83621669.svg @@ -0,0 +1 @@ + diff --git a/assets/js/10.5459967e.js b/assets/js/10.5459967e.js new file mode 100644 index 000000000..404a8d499 --- /dev/null +++ b/assets/js/10.5459967e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{378:function(n,o,l){"use strict";l.r(o);var u=l(26),e=Object(u.a)({},void 0,void 0,!1,null,null,null);o.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/100.70eedb6c.js b/assets/js/100.70eedb6c.js new file mode 100644 index 000000000..6ec5e1478 --- /dev/null +++ b/assets/js/100.70eedb6c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[100],{474:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/101.e7dd71b5.js b/assets/js/101.e7dd71b5.js new file mode 100644 index 000000000..ac35caaa2 --- /dev/null +++ b/assets/js/101.e7dd71b5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[101],{475:function(e,t,r){"use strict";r.r(t);var a=r(26),o=Object(a.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"quartz-net-configuration-reference"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-net-configuration-reference"}},[e._v("#")]),e._v(" Quartz.NET Configuration Reference")]),e._v(" "),r("p"),r("div",{staticClass:"table-of-contents"},[r("ul",[r("li",[r("a",{attrs:{href:"#main-configuration"}},[e._v("Main Configuration")]),r("ul",[r("li",[r("a",{attrs:{href:"#quartz-scheduler-instancename"}},[e._v("quartz.scheduler.instanceName")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-instanceid"}},[e._v("quartz.scheduler.instanceId")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-instanceidgenerator-type"}},[e._v("quartz.scheduler.instanceIdGenerator.type")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-threadname"}},[e._v("quartz.scheduler.threadName")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-makeschedulerthreaddaemon"}},[e._v("quartz.scheduler.makeSchedulerThreadDaemon")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-idlewaittime"}},[e._v("quartz.scheduler.idleWaitTime")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-dbfailureretryinterval"}},[e._v("quartz.scheduler.dbFailureRetryInterval")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-typeloadhelper-type"}},[e._v("quartz.scheduler.typeLoadHelper.type")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-jobfactory-type"}},[e._v("quartz.scheduler.jobFactory.type")])]),r("li",[r("a",{attrs:{href:"#quartz-context-key-some-key"}},[e._v("quartz.context.key.SOME_KEY")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-batchtriggeracquisitionmaxcount"}},[e._v("quartz.scheduler.batchTriggerAcquisitionMaxCount")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-batchtriggeracquisitionfireaheadtimewindow"}},[e._v("quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow")])])])]),r("li",[r("a",{attrs:{href:"#threadpool"}},[e._v("ThreadPool")]),r("ul",[r("li",[r("a",{attrs:{href:"#quartz-threadpool-type"}},[e._v("quartz.threadPool.type")])]),r("li",[r("a",{attrs:{href:"#quartz-threadpool-maxconcurrency"}},[e._v("quartz.threadPool.maxConcurrency")])]),r("li",[r("a",{attrs:{href:"#custom-threadpools"}},[e._v("Custom ThreadPools")])])])]),r("li",[r("a",{attrs:{href:"#listeners"}},[e._v("Listeners")])]),r("li",[r("a",{attrs:{href:"#plug-ins"}},[e._v("Plug-Ins")]),r("ul",[r("li",[r("a",{attrs:{href:"#sample-configuration-of-logging-trigger-history-plugin"}},[e._v("Sample configuration of Logging Trigger History Plugin")])]),r("li",[r("a",{attrs:{href:"#sample-configuration-of-xml-scheduling-data-processor-plugin"}},[e._v("Sample configuration of XML Scheduling Data Processor Plugin")])]),r("li",[r("a",{attrs:{href:"#sample-configuration-of-shutdown-hook-plugin"}},[e._v("Sample configuration of Shutdown Hook Plugin")])]),r("li",[r("a",{attrs:{href:"#sample-configuration-of-job-interrupt-monitor-plugin"}},[e._v("Sample configuration of Job Interrupt Monitor Plugin")])])])]),r("li",[r("a",{attrs:{href:"#remoting-server-and-client"}},[e._v("Remoting Server and Client")]),r("ul",[r("li",[r("a",{attrs:{href:"#quartz-scheduler-exporter-type"}},[e._v("quartz.scheduler.exporter.type")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-exporter-port"}},[e._v("quartz.scheduler.exporter.port")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-exporter-bindname"}},[e._v("quartz.scheduler.exporter.bindName")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-exporter-channeltype"}},[e._v("quartz.scheduler.exporter.channelType")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-exporter-channelname"}},[e._v("quartz.scheduler.exporter.channelName")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-exporter-typefilterlevel"}},[e._v("quartz.scheduler.exporter.typeFilterLevel")])]),r("li",[r("a",{attrs:{href:"#quartz-scheduler-exporter-rejectremoterequests"}},[e._v("quartz.scheduler.exporter.rejectRemoteRequests")])])])]),r("li",[r("a",{attrs:{href:"#ramjobstore"}},[e._v("RAMJobStore")]),r("ul",[r("li",[r("a",{attrs:{href:"#quartz-jobstore-misfirethreshold"}},[e._v("quartz.jobStore.misfireThreshold")])])])]),r("li",[r("a",{attrs:{href:"#jobstoretx-ado-net"}},[e._v("JobStoreTX (ADO.NET)")]),r("ul",[r("li",[r("a",{attrs:{href:"#quartz-jobstore-driverdelegatetype"}},[e._v("quartz.jobStore.driverDelegateType")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-datasource"}},[e._v("quartz.jobStore.dataSource")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-tableprefix"}},[e._v("quartz.jobStore.tablePrefix")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-useproperties"}},[e._v("quartz.jobStore.useProperties")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-misfirethreshold"}},[e._v("quartz.jobStore.misfireThreshold")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-clustered"}},[e._v("quartz.jobStore.clustered")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-clustercheckininterval"}},[e._v("quartz.jobStore.clusterCheckinInterval")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-maxmisfirestohandleatatime"}},[e._v("quartz.jobStore.maxMisfiresToHandleAtATime")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-selectwithlocksql"}},[e._v("quartz.jobStore.selectWithLockSQL")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-txisolationlevelserializable"}},[e._v("quartz.jobStore.txIsolationLevelSerializable")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-acquiretriggerswithinlock"}},[e._v("quartz.jobStore.acquireTriggersWithinLock")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-lockhandler-type"}},[e._v("quartz.jobStore.lockHandler.type")])]),r("li",[r("a",{attrs:{href:"#customizing-stdrowlocksemaphore"}},[e._v("Customizing StdRowLockSemaphore")])]),r("li",[r("a",{attrs:{href:"#quartz-jobstore-driverdelegateinitstring"}},[e._v("quartz.jobStore.driverDelegateInitString")])])])]),r("li",[r("a",{attrs:{href:"#datasources-ado-net-jobstores"}},[e._v("DataSources (ADO.NET JobStores)")]),r("ul",[r("li",[r("a",{attrs:{href:"#quartz-datasource-name-provider"}},[e._v("quartz.dataSource.NAME.provider")])]),r("li",[r("a",{attrs:{href:"#quartz-datasource-name-connectionstring"}},[e._v("quartz.dataSource.NAME.connectionString")])]),r("li",[r("a",{attrs:{href:"#quartz-datasource-name-connectionstringname"}},[e._v("quartz.dataSource.NAME.connectionStringName")])]),r("li",[r("a",{attrs:{href:"#quartz-datasource-name-connectionprovider-type"}},[e._v("quartz.dataSource.NAME.connectionProvider.type")])])])]),r("li",[r("a",{attrs:{href:"#clustering"}},[e._v("Clustering")])])])]),r("p"),e._v(" "),r("p",[e._v("By default, "),r("code",[e._v("StdSchedulerFactory")]),e._v(" loads a properties file named "),r("code",[e._v("quartz.config")]),e._v(' from the "current working directory".\nIf that fails, then the '),r("code",[e._v("quartz.config")]),e._v(" file located (as an embedded resource) in the Quartz dll is loaded.\nIf you wish to use a file other than these defaults, you must define the system property "),r("code",[e._v("quartz.properties")]),e._v(" to point to the file you want.")]),e._v(" "),r("p",[e._v("Alternatively, you can explicitly initialize the factory by calling one of the "),r("code",[e._v("Initialize(xx)")]),e._v(" methods before calling "),r("code",[e._v("GetScheduler()")]),e._v(" on the "),r("code",[e._v("StdSchedulerFactory")]),e._v(".")]),e._v(" "),r("p",[e._v("Instances of the specified "),r("code",[e._v("IJobStore")]),e._v(", "),r("code",[e._v("IThreadPool")]),e._v(", and other SPI types will be created by name, and then any additional properties specified for them in the config file will be set on the instance by calling an equivalent property set method.\nFor example if the properties file contains the property "),r("code",[e._v("quartz.jobStore.myProp = 10")]),e._v(" then after the JobStore type has been instantiated, the setter of property "),r("code",[e._v("MyProp")]),e._v(" will be called on it.\nType conversion to primitive types (int, long, float, double, boolean, and string) are performed before calling the property’s setter method.")]),e._v(" "),r("p",[e._v("One property can reference another property’s value by specifying a value following the convention of "),r("code",[e._v("$@other.property.name")]),e._v(", for example, to reference the scheduler’s instance name as the value for some other property, you would use "),r("code",[e._v("$@quartz.scheduler.instanceName")]),e._v(".")]),e._v(" "),r("div",{staticClass:"custom-block tip"},[r("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),r("p",[e._v("You can also use code-based configuration which essentially builds these keys.")])]),e._v(" "),r("h2",{attrs:{id:"main-configuration"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#main-configuration"}},[e._v("#")]),e._v(" Main Configuration")]),e._v(" "),r("p",[e._v('These properties configure the identification of the scheduler, and various other "top level" settings.')]),e._v(" "),r("table",[r("thead",[r("tr",[r("th",[e._v("Property Name")]),e._v(" "),r("th",[e._v("Required")]),e._v(" "),r("th",[e._v("Type")]),e._v(" "),r("th",[e._v("Default Value")])])]),e._v(" "),r("tbody",[r("tr",[r("td",[e._v("quartz.scheduler.instanceName")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("'QuartzScheduler'")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.instanceId")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("'NON_CLUSTERED'")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.instanceIdGenerator.type")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("Quartz.Simpl.SimpleInstanceIdGenerator, Quartz")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.threadName")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("instanceName + '_QuartzSchedulerThread'")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.makeSchedulerThreadDaemon")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("boolean")]),e._v(" "),r("td",[e._v("false")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.idleWaitTime")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("long")]),e._v(" "),r("td",[e._v("30000")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.dbFailureRetryInterval")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("long")]),e._v(" "),r("td",[e._v("15000")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.typeLoadHelper.type")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("Quartz.Simpl.SimpleTypeLoadHelper")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.jobFactory.type")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("Quartz.Simpl.PropertySettingJobFactory")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.context.key.SOME_KEY")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("none")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.wrapJobExecutionInUserTransaction")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("boolean")]),e._v(" "),r("td",[e._v("false")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.batchTriggerAcquisitionMaxCount")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("int")]),e._v(" "),r("td",[e._v("1")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("long")]),e._v(" "),r("td",[e._v("0")])])])]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-instancename"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-instancename"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.instanceName")])]),e._v(" "),r("p",[e._v("Can be any string, and the value has no meaning to the scheduler itself - but rather serves as a mechanism for client code to distinguish schedulers when multiple instances are used within the same program.\nIf you are using the clustering features, you must use the same name for every instance in the cluster that is 'logically' the same scheduler.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-instanceid"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-instanceid"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.instanceId")])]),e._v(" "),r("p",[e._v('Can be any string, but must be unique for all schedulers working as if they are the same \'logical\' Scheduler within a cluster.\nYou may use the value "AUTO" as the instanceId if you wish the Id to be generated for you.\nOr the value "SYS_PROP" if you want the value to come from the system property "quartz.scheduler.instanceId".')]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-instanceidgenerator-type"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-instanceidgenerator-type"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.instanceIdGenerator.type")])]),e._v(" "),r("p",[e._v('Only used if quartz.scheduler.instanceId is set to "AUTO". Defaults to "Quartz.Simpl.SimpleInstanceIdGenerator",\nwhich generates an instance id based upon host name and time stamp. Other '),r("code",[e._v("InstanceIdGenerator")]),e._v(" implementations include "),r("code",[e._v("SystemPropertyInstanceIdGenerator")]),e._v('\n(which gets the instance id from the system property "quartz.scheduler.instanceId", and '),r("code",[e._v("HostnameInstanceIdGenerator")]),e._v(" which uses the local host name ("),r("code",[e._v("Dns.GetHostEntry(Dns.GetHostName())")]),e._v(").\nYou can also implement the InstanceIdGenerator interface your self.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-threadname"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-threadname"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.threadName")])]),e._v(" "),r("p",[e._v("Can be any string that is a valid name for the main scheduler thread.\nIf this property is not specified, the thread will receive the scheduler’s name (\"quartz.scheduler.instanceName\") plus an the appended string '_QuartzSchedulerThread'.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-makeschedulerthreaddaemon"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-makeschedulerthreaddaemon"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.makeSchedulerThreadDaemon")])]),e._v(" "),r("p",[e._v("A boolean value ('true' or 'false') that specifies whether the main thread of the scheduler should be a daemon thread or not.\nSee also the "),r("code",[e._v("quartz.scheduler.makeSchedulerThreadDaemon")]),e._v(" property for tuning the "),r("code",[e._v("DefaultThreadPool")]),e._v(" if that is the thread pool implementation you are using (which is most likely the case).")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-idlewaittime"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-idlewaittime"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.idleWaitTime")])]),e._v(" "),r("p",[e._v("Is the amount of time in milliseconds that the scheduler will wait before re-queries for available triggers when the scheduler is otherwise idle.\nNormally you should not have to 'tune' this parameter, unless you’re using XA transactions, and are having problems with delayed firings of triggers that should fire immediately.\nValues less than 5000 ms are not recommended as it will cause excessive database querying. Values less than 1000 are not legal.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-dbfailureretryinterval"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-dbfailureretryinterval"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.dbFailureRetryInterval")])]),e._v(" "),r("p",[e._v("Is the amount of time in milliseconds that the scheduler will wait between re-tries when it has detected a loss of connectivity within the JobStore (e.g. to the database).\nThis parameter is obviously not very meaningful when using RamJobStore.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-typeloadhelper-type"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-typeloadhelper-type"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.typeLoadHelper.type")])]),e._v(" "),r("p",[e._v('Defaults to the most robust approach, which is to use the "Quartz.Simpl.SimpleTypeLoadHelper" type - which just loads by using '),r("code",[e._v("Type.GetType()")]),e._v(".")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-jobfactory-type"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-jobfactory-type"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.jobFactory.type")])]),e._v(" "),r("p",[e._v("The type name of the IJobFactory to use. A job factory is responsible for producing instances of "),r("code",[e._v("IJob")]),e._v(" implementations.\nThe default is 'Quartz.Simpl.PropertySettingJobFactory', which simply calls "),r("code",[e._v("Activator.CreateInstance")]),e._v(" with given type to produce a new instance each time execution is about to occur.\n"),r("code",[e._v("PropertySettingJobFactory")]),e._v(" also reflectively sets the job’s properties using the contents of the scheduler context and job and trigger JobDataMaps.")]),e._v(" "),r("h3",{attrs:{id:"quartz-context-key-some-key"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-context-key-some-key"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.context.key.SOME_KEY")])]),e._v(" "),r("p",[e._v('Represent a name-value pair that will be placed into the "scheduler context" as strings (see IScheduler.Context).\nSo for example, the setting "quartz.context.key.MyKey = MyValue" would perform the equivalent of '),r("code",[e._v('scheduler.Context.Put("MyKey", "MyValue")')]),e._v(".")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-batchtriggeracquisitionmaxcount"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-batchtriggeracquisitionmaxcount"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.batchTriggerAcquisitionMaxCount")])]),e._v(" "),r("p",[e._v("The maximum number of triggers that a scheduler node is allowed to acquire (for firing) at once. Default value is 1.\nThe larger the number, the more efficient firing is (in situations where there are very many triggers needing to be fired all at once) -\nbut at the cost of possible imbalanced load between cluster nodes.")]),e._v(" "),r("p",[e._v('If the value of this property is set to > 1, and AdoJobStore is used, then the property "quartz.jobStore.acquireTriggersWithinLock" must be set to "true" to avoid data corruption.')]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-batchtriggeracquisitionfireaheadtimewindow"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-batchtriggeracquisitionfireaheadtimewindow"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow")])]),e._v(" "),r("p",[e._v("The amount of time in milliseconds that a trigger is allowed to be acquired and fired ahead of its scheduled fire time.\nDefaults to 0. The larger the number, the more likely batch acquisition of triggers to fire will be able to select and fire more than 1 trigger at a time -\nat the cost of trigger schedule not being honored precisely (triggers may fire this amount early).")]),e._v(" "),r("p",[e._v("This may be useful (for performance’s sake) in situations where the scheduler has very large numbers of triggers that need to be fired at or near the same time.")]),e._v(" "),r("h2",{attrs:{id:"threadpool"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#threadpool"}},[e._v("#")]),e._v(" ThreadPool")]),e._v(" "),r("table",[r("thead",[r("tr",[r("th",[e._v("Property Name")]),e._v(" "),r("th",[e._v("Required")]),e._v(" "),r("th",[e._v("Type")]),e._v(" "),r("th",[e._v("Default Value")])])]),e._v(" "),r("tbody",[r("tr",[r("td",[e._v("quartz.threadPool.type")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("Quartz.Simpl.DefaultThreadPool")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.threadPool.maxConcurrency")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("int")]),e._v(" "),r("td",[e._v("10")])])])]),e._v(" "),r("h3",{attrs:{id:"quartz-threadpool-type"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-threadpool-type"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.threadPool.type")])]),e._v(" "),r("p",[e._v('Is the name of the ThreadPool implementation you wish to use.\nThe thread pool that ships with Quartz is "Quartz.Simpl.DefaultThreadPool", and should meet the needs of nearly every user.')]),e._v(" "),r("p",[e._v("It has very simple behavior and is very well tested. It dispatches tasks to .NET task queue and ensures that configured max amount of concurrent tasks limit is obeyed.\nYou should study "),r("a",{attrs:{href:"https://docs.microsoft.com/en-us/dotnet/standard/threading/the-managed-thread-pool",target:"_blank",rel:"noopener noreferrer"}},[e._v("CLR's managed thread pool"),r("OutboundLink")],1),e._v(" if you want to fine-tune thread pools on CLR level.")]),e._v(" "),r("h3",{attrs:{id:"quartz-threadpool-maxconcurrency"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-threadpool-maxconcurrency"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.threadPool.maxConcurrency")])]),e._v(" "),r("p",[e._v("This is the number of concurrent tasks that can be dispatched to CLR thread pool.\nIf you only have a few jobs that fire a few times a day, then 1 tasks is plenty!\nIf you have tens of thousands of jobs, with many firing every minute, then you probably want a max concurrency count more like 50 or 100 (this highly depends on the nature of the work that your jobs perform, and your systems resources!).\nAlso note CLR thread pool configuration separate from Quartz itself.")]),e._v(" "),r("h3",{attrs:{id:"custom-threadpools"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#custom-threadpools"}},[e._v("#")]),e._v(" Custom ThreadPools")]),e._v(" "),r("p",[e._v("If you use your own implementation of a thread pool, you can have properties set on it reflectively simply by naming the property as thus:")]),e._v(" "),r("p",[r("strong",[e._v("Setting Properties on a Custom ThreadPool")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.threadPool.type = MyLibrary.FooThreadPool, MyLibrary\nquartz.threadPool.somePropOfFooThreadPool = someValue\n")])])]),r("h2",{attrs:{id:"listeners"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#listeners"}},[e._v("#")]),e._v(" Listeners")]),e._v(" "),r("p",[e._v("Global listeners can be instantiated and configured by "),r("code",[e._v("StdSchedulerFactory")]),e._v(', or your application can do it itself at runtime, and then register the listeners with the scheduler.\n"Global" listeners listen to the events of every job/trigger rather than just the jobs/triggers that directly reference them.')]),e._v(" "),r("p",[e._v("Configuring listeners through the configuration file consists of giving then a name, and then specifying the type name, and any other properties to be set on the instance.\nThe type must have a no-arg constructor, and the properties are set reflectively. Only primitive data type values (including strings) are supported.")]),e._v(" "),r("p",[e._v('Thus, the general pattern for defining a "global" TriggerListener is:')]),e._v(" "),r("p",[r("strong",[e._v("Configuring a Global TriggerListener")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.triggerListener.NAME.type = MyLibrary.MyListenerType, MyLibrary\nquartz.triggerListener.NAME.propName = propValue\nquartz.triggerListener.NAME.prop2Name = prop2Value\n")])])]),r("p",[e._v('And the general pattern for defining a "global" JobListener is:')]),e._v(" "),r("p",[r("strong",[e._v("Configuring a Global JobListener")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.jobListener.NAME.type = MyLibrary.MyListenerType, MyLibrary\nquartz.jobListener.NAME.propName = propValue\nquartz.jobListener.NAME.prop2Name = prop2Value\n")])])]),r("h2",{attrs:{id:"plug-ins"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#plug-ins"}},[e._v("#")]),e._v(" Plug-Ins")]),e._v(" "),r("p",[e._v("Like listeners configuring plugins through the configuration file consists of giving then a name, and then specifying the type name, and any other properties to be set on the instance. The type must have a no-arg constructor, and the properties are set reflectively. Only primitive data type values (including Strings) are supported.")]),e._v(" "),r("p",[e._v("Thus, the general pattern for defining a plug-in is:")]),e._v(" "),r("p",[r("strong",[e._v("Configuring a Plugin")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.plugin.NAME.type = MyLibrary.MyPluginType, MyLibrary\nquartz.plugin.NAME.propName = propValue\nquartz.plugin.NAME.prop2Name = prop2Value\n")])])]),r("p",[e._v("There are several plugins that come with Quartz, that can be found in the "),r("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Plugins",target:"_blank",rel:"noopener noreferrer"}},[e._v("Quartz.Plugins"),r("OutboundLink")],1),e._v(" package.\nExample of configuring a few of them are as follows:")]),e._v(" "),r("h3",{attrs:{id:"sample-configuration-of-logging-trigger-history-plugin"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#sample-configuration-of-logging-trigger-history-plugin"}},[e._v("#")]),e._v(" Sample configuration of Logging Trigger History Plugin")]),e._v(" "),r("p",[e._v("The logging trigger history plugin catches trigger events (it is also a trigger listener) and logs then with logging infrastructure.")]),e._v(" "),r("p",[r("strong",[e._v("Sample configuration of Logging Trigger History Plugin")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.plugin.triggHistory.type = Quartz.Plugin.History.LoggingTriggerHistoryPlugin, Quartz.Plugins\nquartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4:HH:mm:ss MM/dd/yyyy}\nquartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4:HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}\n")])])]),r("h3",{attrs:{id:"sample-configuration-of-xml-scheduling-data-processor-plugin"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#sample-configuration-of-xml-scheduling-data-processor-plugin"}},[e._v("#")]),e._v(" Sample configuration of XML Scheduling Data Processor Plugin")]),e._v(" "),r("p",[e._v("Job initialization plugin reads a set of jobs and triggers from an XML file, and adds them to the scheduler during initialization. It can also delete exiting data.")]),e._v(" "),r("p",[r("strong",[e._v("Sample configuration of JobInitializationPlugin")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.plugin.jobInitializer.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins\nquartz.plugin.jobInitializer.fileNames = data/my_job_data.xml\nquartz.plugin.jobInitializer.failOnFileNotFound = true\n")])])]),r("p",[e._v("The XML schema definition for the file can be found "),r("a",{attrs:{href:"https://github.com/quartznet/quartznet/blob/master/src/Quartz/Xml/job_scheduling_data_2_0.xsd",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),r("OutboundLink")],1),e._v(".")]),e._v(" "),r("h3",{attrs:{id:"sample-configuration-of-shutdown-hook-plugin"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#sample-configuration-of-shutdown-hook-plugin"}},[e._v("#")]),e._v(" Sample configuration of Shutdown Hook Plugin")]),e._v(" "),r("p",[e._v("The shutdown-hook plugin catches the event of the CLR terminating, and calls shutdown on the scheduler.")]),e._v(" "),r("p",[r("strong",[e._v("Sample configuration of ShutdownHookPlugin")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.plugin.shutdownhook.type = Quartz.Plugin.Management.ShutdownHookPlugin, Quartz.Plugins\nquartz.plugin.shutdownhook.cleanShutdown = true\n")])])]),r("h3",{attrs:{id:"sample-configuration-of-job-interrupt-monitor-plugin"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#sample-configuration-of-job-interrupt-monitor-plugin"}},[e._v("#")]),e._v(" Sample configuration of Job Interrupt Monitor Plugin")]),e._v(" "),r("p",[e._v('This plugin catches the event of job running for a long time (more than the configured max time) and tells the scheduler to "try" interrupting it if enabled.\nPlugin defaults to signaling interrupt after 5 minutes, but the default van be configured to something different, value is in milliseconds in configuration.')]),e._v(" "),r("p",[r("strong",[e._v("Sample configuration of JobInterruptMonitorPlugin")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.plugin.jobAutoInterrupt.type = Quartz.Plugin.Interrupt.JobInterruptMonitorPlugin, Quartz.Plugins\nquartz.plugin.jobAutoInterrupt.defaultMaxRunTime = 3000000\n")])])]),r("h2",{attrs:{id:"remoting-server-and-client"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#remoting-server-and-client"}},[e._v("#")]),e._v(" Remoting Server and Client")]),e._v(" "),r("div",{staticClass:"custom-block warning"},[r("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),r("p",[e._v("Remoting only works with .NET Full Framework. It's also considered unsafe.")])]),e._v(" "),r("table",[r("thead",[r("tr",[r("th",[e._v("Property Name")]),e._v(" "),r("th",[e._v("Required")]),e._v(" "),r("th",[e._v("Type")]),e._v(" "),r("th",[e._v("Default Value")])])]),e._v(" "),r("tbody",[r("tr",[r("td",[e._v("quartz.scheduler.exporter.type")]),e._v(" "),r("td",[e._v("yes")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td")]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.exporter.port")]),e._v(" "),r("td",[e._v("yes")]),e._v(" "),r("td",[e._v("int")]),e._v(" "),r("td")]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.exporter.bindName")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("'QuartzScheduler'")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.exporter.channelType")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("'tcp'")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.exporter.channelName")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("'http'")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.exporter.typeFilterLevel")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("'Full'")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.scheduler.exporter.rejectRemoteRequests")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("boolean")]),e._v(" "),r("td",[e._v("false")])])])]),e._v(" "),r("p",[e._v("If you want the Quartz Scheduler to export itself via remoting as a server then set the 'quartz.scheduler.exporter.type' to \"Quartz.Simpl.RemotingSchedulerExporter, Quartz\".")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-exporter-type"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-exporter-type"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.exporter.type")])]),e._v(" "),r("p",[e._v("The type of "),r("code",[e._v("ISchedulerExporter")]),e._v(', currently only "Quartz.Simpl.RemotingSchedulerExporter, Quartz" is supported.')]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-exporter-port"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-exporter-port"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.exporter.port")])]),e._v(" "),r("p",[e._v("The port to listen to.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-exporter-bindname"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-exporter-bindname"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.exporter.bindName")])]),e._v(" "),r("p",[e._v("Name to use when binding to remoting infrastructure.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-exporter-channeltype"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-exporter-channeltype"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.exporter.channelType")])]),e._v(" "),r("p",[e._v("Either 'tcp' or 'http', TCP is more performant.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-exporter-channelname"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-exporter-channelname"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.exporter.channelName")])]),e._v(" "),r("p",[e._v("Channel name to use when binding to remoting infrastructure.")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-exporter-typefilterlevel"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-exporter-typefilterlevel"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.exporter.typeFilterLevel")])]),e._v(" "),r("p",[r("strong",[e._v("Low")])]),e._v(" "),r("p",[e._v("The low deserialization level for .NET Framework remoting. It supports types associated with basic remoting functionality")]),e._v(" "),r("p",[r("strong",[e._v("Full")])]),e._v(" "),r("p",[e._v("The full deserialization level for .NET Framework remoting. It supports all types that remoting supports in all situations")]),e._v(" "),r("h3",{attrs:{id:"quartz-scheduler-exporter-rejectremoterequests"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-scheduler-exporter-rejectremoterequests"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.scheduler.exporter.rejectRemoteRequests")])]),e._v(" "),r("p",[e._v("A boolean value (true or false) that specifies whether to refuse requests from other computers. Specifying true allows only remoting calls from the local computer.")]),e._v(" "),r("h2",{attrs:{id:"ramjobstore"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#ramjobstore"}},[e._v("#")]),e._v(" RAMJobStore")]),e._v(" "),r("p",[e._v("RAMJobStore is used to store scheduling information (job, triggers and calendars) within memory. RAMJobStore is fast and lightweight, but all scheduling information is lost when the process terminates.")]),e._v(" "),r("p",[e._v("RAMJobStore is selected by setting the "),r("code",[e._v("quartz.jobStore.type")]),e._v(" property as such:")]),e._v(" "),r("p",[r("strong",[e._v("Setting The Scheduler’s JobStore to RAMJobStore")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz\n")])])]),r("p",[e._v("RAMJobStore can be tuned with the following properties:")]),e._v(" "),r("table",[r("thead",[r("tr",[r("th",[e._v("Property Name")]),e._v(" "),r("th",[e._v("Required")]),e._v(" "),r("th",[e._v("Type")]),e._v(" "),r("th",[e._v("Default Value")])])]),e._v(" "),r("tbody",[r("tr",[r("td",[e._v("quartz.jobStore.misfireThreshold")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("int")]),e._v(" "),r("td",[e._v("60000")])])])]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-misfirethreshold"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-misfirethreshold"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.misfireThreshold")])]),e._v(" "),r("p",[e._v("The number of milliseconds the scheduler will 'tolerate' a trigger to pass its next-fire-time by, before being considered \"misfired\". The default value (if you don’t make an entry of this property in your configuration) is 60000 (60 seconds).")]),e._v(" "),r("h2",{attrs:{id:"jobstoretx-ado-net"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#jobstoretx-ado-net"}},[e._v("#")]),e._v(" JobStoreTX (ADO.NET)")]),e._v(" "),r("p",[e._v("AdoJobStore is used to store scheduling information (job, triggers and calendars) within a relational database.\nThere are actually two seperate AdoJobStore implementations that you can select between, depending on the transactional behaviour you need.")]),e._v(" "),r("p",[e._v("JobStoreTX manages all transactions itself by calling "),r("code",[e._v("Commit()")]),e._v(" (or "),r("code",[e._v("Rollback()")]),e._v(") on the database connection after every action (such as the addition of a job).\nThis is the job store you should normally be using unless you want to integrate to some transaction-aware framework.")]),e._v(" "),r("p",[e._v("The JobStoreTX is selected by setting the "),r("code",[e._v("quartz.jobStore.type")]),e._v(" property as such:")]),e._v(" "),r("p",[r("strong",[e._v("Setting The Scheduler’s JobStore to JobStoreTX")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz\n")])])]),r("p",[e._v("JobStoreTX can be tuned with the following properties:")]),e._v(" "),r("table",[r("thead",[r("tr",[r("th",[e._v("Property Name")]),e._v(" "),r("th",[e._v("Required")]),e._v(" "),r("th",[e._v("Type")]),e._v(" "),r("th",[e._v("Default Value")])])]),e._v(" "),r("tbody",[r("tr",[r("td",[e._v("quartz.jobStore.driverDelegateType")]),e._v(" "),r("td",[e._v("yes")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("null")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.dataSource")]),e._v(" "),r("td",[e._v("yes")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("null")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.tablePrefix")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v('"QRTZ_"')])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.useProperties")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("boolean")]),e._v(" "),r("td",[e._v("false")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.misfireThreshold")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("int")]),e._v(" "),r("td",[e._v("60000")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.clustered")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("boolean")]),e._v(" "),r("td",[e._v("false")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.clusterCheckinInterval")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("long")]),e._v(" "),r("td",[e._v("15000")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.maxMisfiresToHandleAtATime")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("int")]),e._v(" "),r("td",[e._v("20")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.selectWithLockSQL")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v('"SELECT * FROM {0}LOCKS WHERE SCHED_NAME = {1} AND LOCK_NAME = ? FOR UPDATE"')])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.txIsolationLevelSerializable")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("boolean")]),e._v(" "),r("td",[e._v("false")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.acquireTriggersWithinLock")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("boolean")]),e._v(" "),r("td",[e._v("false (or true - see doc below)")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.lockHandler.type")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("null")])]),e._v(" "),r("tr",[r("td",[e._v("quartz.jobStore.driverDelegateInitString")]),e._v(" "),r("td",[e._v("no")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td",[e._v("null")])])])]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-driverdelegatetype"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-driverdelegatetype"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.driverDelegateType")])]),e._v(" "),r("p",[e._v("Driver delegates understand the particular 'dialects' of varies database systems. Possible built-in choices include:")]),e._v(" "),r("ul",[r("li",[e._v("Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz - default when no specific implementation available")]),e._v(" "),r("li",[e._v("Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz - for Microsoft SQL Server")]),e._v(" "),r("li",[e._v("Quartz.Impl.AdoJobStore.PostgreSQLDelegate, Quartz")]),e._v(" "),r("li",[e._v("Quartz.Impl.AdoJobStore.OracleDelegate, Quartz")]),e._v(" "),r("li",[e._v("Quartz.Impl.AdoJobStore.SQLiteDelegate, Quartz")]),e._v(" "),r("li",[e._v("Quartz.Impl.AdoJobStore.MySQLDelegate, Quartz")])]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-datasource"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-datasource"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.dataSource")])]),e._v(" "),r("p",[e._v("The value of this property must be the name of one the DataSources defined in the configuration properties file.")]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-tableprefix"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-tableprefix"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.tablePrefix")])]),e._v(" "),r("p",[e._v('AdoJobStore’s "table prefix" property is a string equal to the prefix given to Quartz’s tables that were created in your database.\nYou can have multiple sets of Quartz’s tables within the same database if they use different table prefixes.')]),e._v(" "),r("p",[r("strong",[e._v("Including schema name in tablePrefix")])]),e._v(" "),r("p",[e._v("For backing databases that support schemas (such as Microsoft SQL Server), you may use the tablePrefix to include the schema name. i.e. for a schema named "),r("code",[e._v("foo")]),e._v(" the prefix could be set as:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("[foo].QRTZ_\n")])])]),r("p",[r("strong",[e._v("Note:")]),e._v(" Any database table create scripts that were run with an explicit schema (such as "),r("code",[e._v("dbo")]),e._v("), will need to be modified to reflect this configuration.")]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-useproperties"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-useproperties"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.useProperties")])]),e._v(" "),r("p",[e._v('The "use properties" flag instructs AdoJobStore that all values in JobDataMaps will be strings, and therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column.\nThis is can be handy, as you avoid the type versioning issues that can arise from serializing your non-string types into a BLOB.')]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-misfirethreshold-2"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-misfirethreshold-2"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.misfireThreshold")])]),e._v(" "),r("p",[e._v("The number of milliseconds the scheduler will 'tolerate' a trigger to pass its next-fire-time by, before being considered \"misfired\".\nThe default value (if you don’t make an entry of this property in your configuration) is 60000 (60 seconds).")]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-clustered"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-clustered"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.clustered")])]),e._v(" "),r("p",[e._v('Set to "true" in order to turn on clustering features.\nThis property must be set to "true" if you are having multiple instances of Quartz use the same set of database tables…​ otherwise you will experience havoc.\nSee the configuration docs for clustering for more information.')]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-clustercheckininterval"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-clustercheckininterval"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.clusterCheckinInterval")])]),e._v(" "),r("p",[e._v('Set the frequency (in milliseconds) at which this instance "checks-in"* with the other instances of the cluster. Affects the quickness of detecting failed instances.')]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-maxmisfirestohandleatatime"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-maxmisfirestohandleatatime"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.maxMisfiresToHandleAtATime")])]),e._v(" "),r("p",[e._v("The maximum number of misfired triggers the job store will handle in a given pass.\nHandling many (more than a couple dozen) at once can cause the database tables to be locked long enough that the performance of firing other (not yet misfired) triggers may be hampered.")]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-selectwithlocksql"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-selectwithlocksql"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.selectWithLockSQL")])]),e._v(" "),r("p",[e._v('Must be a SQL string that selects a row in the "LOCKS" table and places a lock on the row. If not set, the default is "SELECT * FROM {0}LOCKS WHERE SCHED_NAME = {1} AND LOCK_NAME = ? FOR UPDATE", which works for most databases.\nThe "{0}" is replaced during run-time with the TABLE_PREFIX that you configured above.\nThe "{1}" is replaced with the scheduler’s name.')]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-txisolationlevelserializable"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-txisolationlevelserializable"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.txIsolationLevelSerializable")])]),e._v(" "),r("p",[e._v('A value of "true" tells Quartz (when using JobStoreTX or CMT) to set transction level to serialize on ADO.NET connections.\nThis can be helpful to prevent lock timeouts with some databases under high load, and "long-lasting" transactions.')]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-acquiretriggerswithinlock"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-acquiretriggerswithinlock"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.acquireTriggersWithinLock")])]),e._v(" "),r("p",[e._v('Whether or not the acquisition of next triggers to fire should occur within an explicit database lock.\nThis was once necessary (in previous versions of Quartz) to avoid dead-locks with particular databases, but is no longer considered necessary, hence the default value is "false".')]),e._v(" "),r("p",[e._v('If "quartz.scheduler.batchTriggerAcquisitionMaxCount" is set to > 1, and AdoJobStore is used, then this property must be set to "true" to avoid data corruption\n(as of Quartz 2 "true" is now the default if batchTriggerAcquisitionMaxCount is set > 1).')]),e._v(" "),r("h3",{attrs:{id:"quartz-jobstore-lockhandler-type"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-lockhandler-type"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.lockHandler.type")])]),e._v(" "),r("p",[e._v("The type name to be used to produce an instance of a "),r("code",[e._v("Quartz.Impl.AdoJobStore.ISemaphore")]),e._v(" to be used for locking control on the job store data.\nThis is an advanced configuration feature, which should not be used by most users.")]),e._v(" "),r("p",[e._v("By default, Quartz will select the most appropriate (pre-bundled) Semaphore implementation to use.")]),e._v(" "),r("h3",{attrs:{id:"customizing-stdrowlocksemaphore"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#customizing-stdrowlocksemaphore"}},[e._v("#")]),e._v(" Customizing StdRowLockSemaphore")]),e._v(" "),r("p",[e._v("If you explicitly choose to use this DB Semaphore, you can customize it further on how frequent to poll for DB locks.")]),e._v(" "),r("p",[r("strong",[e._v("Example of Using a Custom StdRowLockSemaphore Implementation")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.jobStore.lockHandler.type = Quartz.Impl.AdoJobStore.StdRowLockSemaphore\nquartz.jobStore.lockHandler.maxRetry = 7 # Default is 3\nquartz.jobStore.lockHandler.retryPeriod = 3000 # Default is 1000 millis\n")])])]),r("h3",{attrs:{id:"quartz-jobstore-driverdelegateinitstring"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-jobstore-driverdelegateinitstring"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.jobStore.driverDelegateInitString")])]),e._v(" "),r("p",[e._v("A pipe-delimited list of properties (and their values) that can be passed to the DriverDelegate during initialization time.")]),e._v(" "),r("p",[e._v("The format of the string is as such:")]),e._v(" "),r("p",[r("code",[e._v("settingName=settingValue|otherSettingName=otherSettingValue|...")])]),e._v(" "),r("p",[e._v("The StdAdoDelegate and all of its descendants (all delegates that ship with Quartz) support a property called 'triggerPersistenceDelegateTypes' which can be set to a comma-separated list of types that implement the "),r("code",[e._v("ITriggerPersistenceDelegate")]),e._v(" interface for storing custom trigger types.\nSee the implementations "),r("code",[e._v("SimplePropertiesTriggerPersistenceDelegateSupport")]),e._v(" and "),r("code",[e._v("SimplePropertiesTriggerPersistenceDelegateSupport")]),e._v(" for examples of writing a persistence delegate for a custom trigger.")]),e._v(" "),r("h2",{attrs:{id:"datasources-ado-net-jobstores"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#datasources-ado-net-jobstores"}},[e._v("#")]),e._v(" DataSources (ADO.NET JobStores)")]),e._v(" "),r("p",[e._v("If you’re using AdoJobstore, you’ll be needing a DataSource for its use (or two DataSources, if you’re using JobStoreCMT).")]),e._v(" "),r("p",[e._v('Each DataSource you define (typically one or two) must be given a name, and the properties you define for each must contain that name, as shown below. The DataSource’s "NAME" can be anything you want, and has no meaning other than being able to identify it when it is assigned to the AdoJobStore.')]),e._v(" "),r("p",[e._v("Quartz-created DataSources are defined with the following properties:")]),e._v(" "),r("table",[r("thead",[r("tr",[r("th",[e._v("Property Name")]),e._v(" "),r("th",[e._v("Required")]),e._v(" "),r("th",[e._v("Type")]),e._v(" "),r("th",[e._v("Default Value")])])]),e._v(" "),r("tbody",[r("tr",[r("td",[e._v("quartz.dataSource.NAME.provider")]),e._v(" "),r("td",[e._v("yes")]),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td")]),e._v(" "),r("tr",[r("td",[e._v("quartz.dataSource.NAME.connectionString")]),e._v(" "),r("td"),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td")]),e._v(" "),r("tr",[r("td",[e._v("quartz.dataSource.NAME.connectionStringName")]),e._v(" "),r("td"),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td")]),e._v(" "),r("tr",[r("td",[e._v("quartz.dataSource.NAME.connectionProvider.type")]),e._v(" "),r("td"),e._v(" "),r("td",[e._v("string")]),e._v(" "),r("td")])])]),e._v(" "),r("h3",{attrs:{id:"quartz-datasource-name-provider"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-datasource-name-provider"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.dataSource.NAME.provider")])]),e._v(" "),r("p",[e._v("Currently following database providers are supported:")]),e._v(" "),r("ul",[r("li",[r("code",[e._v("SqlServer")]),e._v(" - Microsoft SQL Server")]),e._v(" "),r("li",[r("code",[e._v("OracleODP")]),e._v(" - Oracle's Oracle Driver")]),e._v(" "),r("li",[r("code",[e._v("OracleODPManaged")]),e._v(" - Oracle's managed driver for Oracle 11")]),e._v(" "),r("li",[r("code",[e._v("MySql")]),e._v(" - MySQL Connector/.NET")]),e._v(" "),r("li",[r("code",[e._v("SQLite")]),e._v(" - SQLite ADO.NET Provider")]),e._v(" "),r("li",[r("code",[e._v("SQLite-Microsoft")]),e._v(" - Microsoft SQLite ADO.NET Provider")]),e._v(" "),r("li",[r("code",[e._v("Firebird")]),e._v(" - Firebird ADO.NET Provider")]),e._v(" "),r("li",[r("code",[e._v("Npgsql")]),e._v(" - PostgreSQL Npgsql")])]),e._v(" "),r("h3",{attrs:{id:"quartz-datasource-name-connectionstring"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-datasource-name-connectionstring"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.dataSource.NAME.connectionString")])]),e._v(" "),r("p",[e._v("ADO.NET connection string to use. You can skip this if you are using connectionStringName below.")]),e._v(" "),r("h3",{attrs:{id:"quartz-datasource-name-connectionstringname"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-datasource-name-connectionstringname"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.dataSource.NAME.connectionStringName")])]),e._v(" "),r("p",[e._v("Connection string name to use. Defined either in app.config or appsettings.json.")]),e._v(" "),r("h3",{attrs:{id:"quartz-datasource-name-connectionprovider-type"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-datasource-name-connectionprovider-type"}},[e._v("#")]),e._v(" "),r("code",[e._v("quartz.dataSource.NAME.connectionProvider.type")])]),e._v(" "),r("p",[e._v("Allows you to define a custom connection provider implementing IDbProvider interface.")]),e._v(" "),r("p",[r("strong",[e._v("Example of a Quartz-defined DataSource")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("quartz.dataSource.myDS.provider = SqlServer\nquartz.dataSource.myDS.connectionString = Server=localhost;Database=quartznet;User Id=quartznet;Password=quartznet;\n")])])]),r("h2",{attrs:{id:"clustering"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#clustering"}},[e._v("#")]),e._v(" Clustering")]),e._v(" "),r("p",[e._v("Quartz’s clustering features bring both high availability and scalability to your scheduler via fail-over and load balancing functionality.")]),e._v(" "),r("p",[e._v("Clustering currently only works with the AdoJobstore ("),r("code",[e._v("JobStoreTX")]),e._v(" or "),r("code",[e._v("JobStoreCMT")]),e._v("), and essentially works by having each node of the cluster share the same database.")]),e._v(" "),r("p",[e._v("Load-balancing occurs automatically, with each node of the cluster firing jobs as quickly as it can. When a trigger’s firing time occurs, the first node to acquire it (by placing a lock on it) is the node that will fire it.")]),e._v(" "),r("p",[e._v("Only one node will fire the job for each firing.\nWhat I mean by that is, if the job has a repeating trigger that tells it to fire every 10 seconds, then at 12:00:00 exactly one node will run the job, and at 12:00:10 exactly one node will run the job, etc.\nIt won’t necessarily be the same node each time - it will more or less be random which node runs it.\nThe load balancing mechanism is near-random for busy schedulers (lots of triggers) but favors the same node for non-busy (e.g. few triggers) schedulers.")]),e._v(" "),r("p",[e._v('Fail-over occurs when one of the nodes fails while in the midst of executing one or more jobs. When a node fails, the other nodes detect the condition and identify the jobs in the database that were in progress within the failed node.\nAny jobs marked for recovery (with the "requests recovery" property on the JobDetail) will be re-executed by the remaining nodes. Jobs not marked for recovery will simply be freed up for execution at the next time a related trigger fires.')]),e._v(" "),r("p",[e._v("The clustering feature works best for scaling out long-running and/or cpu-intensive jobs (distributing the work-load over multiple nodes).\nIf you need to scale out to support thousands of short-running (e.g 1 second) jobs, consider partitioning the set of jobs by using multiple distinct schedulers (including multiple clustered schedulers for HA).\nThe scheduler makes use of a cluster-wide lock, a pattern that degrades performance as you add more nodes (when going beyond about three nodes - depending upon your database’s capabilities, etc.).")]),e._v(" "),r("p",[e._v("Enable clustering by setting the "),r("code",[e._v("quartz.jobStore.clustered")]),e._v(' property to "true". Each instance in the cluster should use the same copy of the quartz.properties file.\nExceptions of this would be to use properties files that are identical, with the following allowable exceptions: Different thread pool size, and different value for the '),r("code",[e._v("quartz.scheduler.instanceId")]),e._v(' property.\nEach node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing "AUTO" as the value of this property.\nSee the info about the configuration properties of AdoJobStore for more information.')]),e._v(" "),r("div",{staticClass:"custom-block danger"},[r("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),r("p",[e._v("Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly (the clocks must be within a second of each other).\nSee "),r("a",{attrs:{href:"https://www.nist.gov/pml/time-and-frequency-division/services/internet-time-service-its",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://www.nist.gov/pml/time-and-frequency-division/services/internet-time-service-its"),r("OutboundLink")],1),e._v(" if you are unfamiliar with how to do this.")])]),e._v(" "),r("div",{staticClass:"custom-block danger"},[r("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),r("p",[e._v("Never start ("),r("code",[e._v("scheduler.Start()")]),e._v(") a non-clustered instance against the same set of database tables that any other instance is running ("),r("code",[e._v("Start()")]),e._v("ed) against.\nYou may get serious data corruption, and will definitely experience erratic behavior.")])]),e._v(" "),r("div",{staticClass:"custom-block danger"},[r("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),r("p",[e._v("Monitor and ensure that your nodes have enough CPU resources to complete jobs.\nWhen some nodes are in 100% CPU, they may be unable to update the job store and other nodes can consider these jobs lost and recover them by re-running.")])]),e._v(" "),r("p",[r("strong",[e._v("Example Properties For A Clustered Scheduler")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("#============================================================================\n# Configure Main Scheduler Properties\n#============================================================================\n\nquartz.scheduler.instanceName = MyClusteredScheduler\nquartz.scheduler.instanceId = AUTO\n\n#============================================================================\n# Configure ThreadPool\n#============================================================================\n\nquartz.threadPool.type = Quartz.Simpl.DefaultThreadPool, Quartz\nquartz.threadPool.threadCount = 25\nquartz.threadPool.threadPriority = 5\n\n#============================================================================\n# Configure JobStore\n#============================================================================\n\nquartz.jobStore.misfireThreshold = 60000\n\nquartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX\nquartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.SqlServerDelegate\nquartz.jobStore.useProperties = true\nquartz.jobStore.dataSource = myDS\nquartz.jobStore.tablePrefix = QRTZ_\n\nquartz.jobStore.clustered = true\nquartz.jobStore.clusterCheckinInterval = 20000\n\n#============================================================================\n# Configure Datasources\n#============================================================================\n\nquartz.dataSource.myDS.provider = SqlServer\nquartz.dataSource.myDS.connectionString = Server=localhost;Database=quartznet;User Id=quartznet;Password=quartznet;\n")])])])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/102.d099ddb5.js b/assets/js/102.d099ddb5.js new file mode 100644 index 000000000..ae98dba91 --- /dev/null +++ b/assets/js/102.d099ddb5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[102],{476:function(t,a,e){"use strict";e.r(a);var s=e(26),r=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("p",[e("em",[t._v("This document outlines changes needed per version upgrade basis. You need to check the steps for each version you are jumping over. You should also check "),e("a",{attrs:{href:"https://raw.github.com/quartznet/quartznet/master/changelog.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("the complete change log"),e("OutboundLink")],1),t._v(".")])]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),e("p",[t._v("If you are a new user starting with the latest version, you don't need to follow this guide. Just jump right to "),e("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/index.html"}},[t._v("the tutorial")])],1)]),t._v(" "),e("p",[t._v("Quartz jumped to async/await world and added support for .NET Core with 3.0 release so most significant changes\ncan be found on APIs and functionality available depending on whether you target full .NET Framework or the .NET Core.")]),t._v(" "),e("h2",{attrs:{id:"packaging-changes"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#packaging-changes"}},[t._v("#")]),t._v(" Packaging changes")]),t._v(" "),e("p",[t._v("Quartz NuGet package was split to more specific packages.")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Jobs",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Jobs"),e("OutboundLink")],1),t._v(" is now a separate NuGet dependency you might need\n"),e("ul",[e("li",[t._v("DirectoryScanJob")]),t._v(" "),e("li",[t._v("FileScanJob")]),t._v(" "),e("li",[t._v("NativeJob")]),t._v(" "),e("li",[t._v("SendMailJob")])])]),t._v(" "),e("li",[e("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Plugins",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Plugins"),e("OutboundLink")],1),t._v(" is now a separate NuGet dependency you might need\n"),e("ul",[e("li",[t._v("XMLSchedulingDataProcessorPlugin")])])])]),t._v(" "),e("p",[t._v("Check that you reference the required NuGet packages and that your configuration references also the correct assembly.")]),t._v(" "),e("h3",{attrs:{id:"database-schema-changes"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#database-schema-changes"}},[t._v("#")]),t._v(" Database schema changes")]),t._v(" "),e("p",[t._v("2.6 schema should work with 3.0 with no changes.")]),t._v(" "),e("h3",{attrs:{id:"migrating-holidaycalendar-binary-format"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#migrating-holidaycalendar-binary-format"}},[t._v("#")]),t._v(" Migrating HolidayCalendar binary format")]),t._v(" "),e("p",[t._v("If you have "),e("code",[t._v("HolidayCalendar")]),t._v("s stored in database in binary format (just stored with AdoJobStore). You need to first load them with Quartz 2.4 or later 2.x version and then re-store them.\nThis will make the serialization use format that is not dependant on precense of C5 library.")]),t._v(" "),e("h3",{attrs:{id:"thread-pool-changes"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#thread-pool-changes"}},[t._v("#")]),t._v(" Thread pool changes")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("SimpleThreadPool")]),t._v(" was removed altogether and it's now a synonym for "),e("code",[t._v("DefaultThreadPool")])]),t._v(" "),e("li",[t._v("Jobs are now ran in CLR thread pool")]),t._v(" "),e("li",[e("code",[t._v("ThreadCount")]),t._v(" parameter still limits how many items will be queued at most to CLR thread pool")]),t._v(" "),e("li",[t._v("Thread priority is no longer supported, you need to remove "),e("code",[t._v("threadPriority")]),t._v(" parameter")])]),t._v(" "),e("h3",{attrs:{id:"api-changes"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#api-changes"}},[t._v("#")]),t._v(" API Changes")]),t._v(" "),e("p",[t._v("Scheduler and job API methods now are based on Tasks. This reflects how you define your jobs and operate with scheduler.")]),t._v(" "),e("h4",{attrs:{id:"scheduler"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#scheduler"}},[t._v("#")]),t._v(" Scheduler")]),t._v(" "),e("p",[t._v("You now need to make sure that you have proper awaits in place when you operate with the scheduler:")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// operating with scheduler is now Task-based and requires appropriate awaits")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Shutdown")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token named-parameter punctuation"}},[t._v("waitForJobsToComplete")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("h4",{attrs:{id:"jobs"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#jobs"}},[t._v("#")]),t._v(" Jobs")]),t._v(" "),e("p",[t._v("Job's Execute method now returns a Task and can easily contain async code:")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Jobs now return tasks from their Execute methods")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyJob")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token type-list"}},[e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// dummy 1ms sleep")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Task"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Delay")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),e("p",[t._v("If you don't have any async'ness in your job, you can just return "),e("code",[t._v("Task.CompletedTask")]),t._v(" at the end of Execute method (available from .NET 4.6 onwards).")]),t._v(" "),e("h5",{attrs:{id:"iinterruptablejob"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#iinterruptablejob"}},[t._v("#")]),t._v(" IInterruptableJob")]),t._v(" "),e("p",[e("code",[t._v("IInterruptableJob")]),t._v(" interface has been removed. You need to check for "),e("code",[t._v("IJobExecutionContext")]),t._v("'s"),e("code",[t._v("CancellationToken.IsCancellationRequested")]),t._v(" to determine whether job interruption has been requested.")]),t._v(" "),e("h5",{attrs:{id:"istatefuljob"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#istatefuljob"}},[t._v("#")]),t._v(" IStatefulJob")]),t._v(" "),e("p",[e("code",[t._v("IStatefulJob")]),t._v(" interface that was obsoleted in 2.x has been removed, you should use "),e("code",[t._v("DisallowConcurrentExecution")]),t._v(" and "),e("code",[t._v("PersistJobDataAfterExecution")]),t._v(" attributes to achieve your goal.")]),t._v(" "),e("h4",{attrs:{id:"other-apis"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#other-apis"}},[t._v("#")]),t._v(" Other APIs")]),t._v(" "),e("p",[t._v("If you have created custom implementations of services used by Quartz, you're going to need to adapt your code to be async-based.")]),t._v(" "),e("h3",{attrs:{id:"job-store-serialization-configuration-changes"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#job-store-serialization-configuration-changes"}},[t._v("#")]),t._v(" Job store serialization configuration changes")]),t._v(" "),e("p",[t._v("You need to now explicitly state whether you want to use binary or json serialization if you are using persistent job store (AdoJobStore) when you configure your scheduler.")]),t._v(" "),e("ul",[e("li",[t._v("For existing setups you should use the old binary serialization to ensure things work like before (see "),e("RouterLink",{attrs:{to:"/documentation/quartz-3.x/packages/json-serialization.html"}},[t._v("Quartz.Serialization.Json documentation")]),t._v(" for migration path)")],1),t._v(" "),e("li",[t._v("For new projects the JSON serialization is recommended as it should be marginally faster and more robust as it's not dealing with binary versioning issues")]),t._v(" "),e("li",[t._v("JSON is more secure and generally the way to use moving forward")])]),t._v(" "),e("p",[t._v("If you choose to go with JSON serialization, remember to add NuGet package reference "),e("strong",[e("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Serialization.Json/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Serialization.Json"),e("OutboundLink")],1)]),t._v(" to your project.")]),t._v(" "),e("p",[t._v("Configuring binary serialization strategy:")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" properties "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NameValueCollection")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.jobStore.type"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// "binary" is alias for "Quartz.Simpl.BinaryObjectSerializer, Quartz" ')]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.serializer.type"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"binary"')]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" sf "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("properties"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("p",[t._v("Configuring JSON serialization strategy (recommended):")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" properties "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NameValueCollection")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.jobStore.type"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// "json" is alias for "Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json" ')]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.serializer.type"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"json"')]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" sf "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("properties"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("h2",{attrs:{id:"simplified-job-store-provider-names"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#simplified-job-store-provider-names"}},[t._v("#")]),t._v(" Simplified job store provider names")]),t._v(" "),e("p",[t._v("ADO.NET provider names have been simplified, the provider names are without version, e.g. "),e("code",[t._v("SqlServer-20")]),t._v(" => "),e("code",[t._v("SqlServer")]),t._v(". They are now bound to whatever version that can be loaded.")]),t._v(" "),e("h3",{attrs:{id:"c5-collections"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#c5-collections"}},[t._v("#")]),t._v(" C5 Collections")]),t._v(" "),e("p",[t._v("C5 Collections are no longer ILMerged inside Quartz, .NET 4.5 offers the needed collections.")]),t._v(" "),e("h3",{attrs:{id:"logging"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#logging"}},[t._v("#")]),t._v(" Logging")]),t._v(" "),e("p",[t._v("Common.Logging has been replaced with "),e("a",{attrs:{href:"https://github.com/damianh/LibLog",target:"_blank",rel:"noopener noreferrer"}},[t._v("LibLog"),e("OutboundLink")],1),t._v(" to reduce dependencies to none. LibLog should automatically detect your logging framework of choice if it's supported.")]),t._v(" "),e("h3",{attrs:{id:"remoting"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#remoting"}},[t._v("#")]),t._v(" Remoting")]),t._v(" "),e("p",[t._v("Remoting is currently only supported when running on full framework version.")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/103.4cce09e1.js b/assets/js/103.4cce09e1.js new file mode 100644 index 000000000..65aa368ed --- /dev/null +++ b/assets/js/103.4cce09e1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[103],{477:function(t,s,a){"use strict";a.r(s);var e=a(26),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.AspNetCore",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.AspNetCore"),a("OutboundLink")],1),t._v("\nprovides integration with "),a("a",{attrs:{href:"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services",target:"_blank",rel:"noopener noreferrer"}},[t._v("ASP.NET Core hosted services"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("If you only need the generic host, "),a("a",{attrs:{href:"hosted-services-integration"}},[t._v("generic host integration")]),t._v(" might suffice.")])]),t._v(" "),a("h2",{attrs:{id:"installation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),a("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[t._v("Install-Package Quartz.AspNetCore\n")])])]),a("h2",{attrs:{id:"using"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using"}},[t._v("#")]),t._v(" Using")]),t._v(" "),a("p",[t._v("You can add Quartz configuration by invoking an extension method "),a("code",[t._v("AddQuartzServer")]),t._v(" on "),a("code",[t._v("IServiceCollection")]),t._v(".\nThis will add a hosted quartz server into ASP.NET Core process that will be started and stopped based on applications lifetime.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("See "),a("a",{attrs:{href:"microsoft-di-integration"}},[t._v("Quartz.Extensions.DependencyInjection documentation")]),t._v(" to learn more about configuring Quartz scheduler, jobs and triggers.")])]),t._v(" "),a("p",[a("strong",[t._v("Example Startup.ConfigureServices configuration")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ConfigureServices")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IServiceCollection")]),t._v(" services"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n services"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartz")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("q "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// base quartz scheduler, job and trigger configuration")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ASP.NET Core hosting")]),t._v("\n services"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartzServer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// when shutting down we want jobs to complete gracefully")]),t._v("\n options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("WaitForJobsToComplete "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/104.8a143487.js b/assets/js/104.8a143487.js new file mode 100644 index 000000000..58b610ca8 --- /dev/null +++ b/assets/js/104.8a143487.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[104],{478:function(t,s,n){"use strict";n.r(s);var a=n(26),e=Object(a.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[n("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Extensions.Hosting",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Extensions.Hosting"),n("OutboundLink")],1),t._v("\nprovides integration with "),n("a",{attrs:{href:"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services",target:"_blank",rel:"noopener noreferrer"}},[t._v("hosted services"),n("OutboundLink")],1),t._v(".")]),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),n("p",[t._v("Quartz 3.2 or later required for Quartz.Extensions.Hosting. You can use package Quartz.AspNetCore with version 3.1.")])]),t._v(" "),n("h2",{attrs:{id:"installation"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),n("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),n("p",[n("strong",[t._v("Quartz 3.1")])]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v("Install-Package Quartz.AspNetCore \n")])])]),n("p",[n("strong",[t._v("Quartz 3.2 onwards")])]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v("Install-Package Quartz.Extensions.Hosting\n")])])]),n("h2",{attrs:{id:"using"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#using"}},[t._v("#")]),t._v(" Using")]),t._v(" "),n("p",[t._v("You can add Quartz configuration by invoking an extension method "),n("code",[t._v("AddQuartzHostedService")]),t._v(" on "),n("code",[t._v("IServiceCollection")]),t._v(".\nThis will add a hosted quartz server into process that will be started and stopped based on applications lifetime.")]),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),n("p",[t._v("See "),n("a",{attrs:{href:"microsoft-di-integration"}},[t._v("Quartz.Extensions.DependencyInjection documentation")]),t._v(" to learn more about configuring Quartz scheduler, jobs and triggers.")])]),t._v(" "),n("p",[n("strong",[t._v("Example program utilizing hosted services configuration")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Program")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token return-type class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Main")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" args"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Log"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Logger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("LoggerConfiguration")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Enrich"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromLogContext")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("WriteTo"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Console")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("CreateLogger")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("CreateHostBuilder")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Run")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("IHostBuilder")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("CreateHostBuilder")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" args"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n Host"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("CreateDefaultBuilder")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseSerilog")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ConfigureServices")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("hostContext"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// see Quartz.Extensions.DependencyInjection documentation about how to configure different configuration aspects")]),t._v("\n services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartz")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("q "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// your configuration here")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Quartz.Extensions.Hosting hosting")]),t._v("\n services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartzHostedService")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// when shutting down we want jobs to complete gracefully")]),t._v("\n options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("WaitForJobsToComplete "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/105.bbb1e2b5.js b/assets/js/105.bbb1e2b5.js new file mode 100644 index 000000000..17588ffda --- /dev/null +++ b/assets/js/105.bbb1e2b5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[105],{479:function(t,s,a){"use strict";a.r(s);var n=a(26),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("JSON is recommended persistent format to store data in database for greenfield projects.\nYou should also strongly consider setting useProperties to true to restrict key-values to be strings.")])]),t._v(" "),a("p",[a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Serialization.Json",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Serialization.Json"),a("OutboundLink")],1),t._v(" provides JSON serialization support for job stores using\n"),a("a",{attrs:{href:"https://www.newtonsoft.com/json",target:"_blank",rel:"noopener noreferrer"}},[t._v("Json.NET"),a("OutboundLink")],1),t._v(" to handle the actual serialization process.")]),t._v(" "),a("h2",{attrs:{id:"installation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),a("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[t._v("Install-Package Quartz.Serialization.Json\n")])])]),a("h2",{attrs:{id:"configuring"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#configuring"}},[t._v("#")]),t._v(" Configuring")]),t._v(" "),a("p",[a("strong",[t._v("Classic property-based configuration")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" properties "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NameValueCollection")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.jobStore.type"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// "json" is alias for "Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json" ')]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.serializer.type"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"json"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" schedulerFactory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("properties"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Configuring using scheduler builder")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" config "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" SchedulerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nconfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsePersistentStore")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("store "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// it's generally recommended to stick with")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// string property keys and values when serializing")]),t._v("\n store"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UseProperties "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n store"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseGenericDatabase")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dbProvider"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" db "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n db"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ConnectionString "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my connection string"')]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n store"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseJsonSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" schedulerFactory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h2",{attrs:{id:"migrating-from-binary-serialization"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#migrating-from-binary-serialization"}},[t._v("#")]),t._v(" Migrating from binary serialization")]),t._v(" "),a("p",[t._v("There's now official solution for migration as there can be quirks in every setup, but there's a recipe that can work for you.")]),t._v(" "),a("ul",[a("li",[t._v("Configure custom serializer like "),a("code",[t._v("MigratorSerializer")]),t._v(" below that can read binary serialization format and writes JSON format")]),t._v(" "),a("li",[t._v("Either let system gradually migrate as it's running or create a program which loads and writes back to DB all relevant serialized assets")])]),t._v(" "),a("p",[a("strong",[t._v("Example hybrid serializer")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MigratorSerializer")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IObjectSerializer")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BinaryObjectSerializer")]),t._v(" binarySerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JsonObjectSerializer")]),t._v(" jsonSerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("MigratorSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("binarySerializer "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("BinaryObjectSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// you might need custom configuration, see sections about customizing")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// in documentation")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("jsonSerializer "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JsonObjectSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("T")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("DeSerialize")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("T"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("byte")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" data"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("T")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Attempt to deserialize data as JSON")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("jsonSerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("DeSerialize")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("T"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JsonReaderException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Presumably, the data was not JSON, we instead use the binary serializer")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("binarySerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("DeSerialize")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("T"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Initialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("binarySerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Initialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("jsonSerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Initialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("byte")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Serialize")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("T"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("T")]),t._v(" obj"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("T")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("jsonSerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Serialize")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("T"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("obj"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h2",{attrs:{id:"customizing-json-net"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#customizing-json-net"}},[t._v("#")]),t._v(" Customizing JSON.NET")]),t._v(" "),a("p",[t._v("If you need to customize JSON.NET settings, you need to inherit custom implementation and override "),a("code",[t._v("CreateSerializerSettings")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CustomJsonSerializer")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JsonObjectSerializer")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("JsonSerializerSettings")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("CreateSerializerSettings")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" settings "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("base")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("CreateSerializerSettings")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n settings"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Converters"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Add")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("MyCustomConverter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" settings"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),a("p",[a("strong",[t._v("And then configure it to use")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("store"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseSerializer")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("CustomJsonSerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// or ")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.serializer.type"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"MyProject.CustomJsonSerializer, MyProject"')]),t._v("\n")])])]),a("h2",{attrs:{id:"customizing-calendar-serialization"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#customizing-calendar-serialization"}},[t._v("#")]),t._v(" Customizing calendar serialization")]),t._v(" "),a("p",[t._v("If you have implemented a custom calendar, you need to implement a "),a("code",[t._v("ICalendarSerializer")]),t._v(" for it.\nThere's a convenience base class "),a("code",[t._v("CalendarSerializer")]),t._v(" that you can use the get strongly-typed experience.")]),t._v(" "),a("p",[a("strong",[t._v("Custom calendar and serializer")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token attribute"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Serializable")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CustomCalendar")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BaseCalendar")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("CustomCalendar")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// binary serialization support")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("CustomCalendar")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SerializationInfo")]),t._v(" info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StreamingContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("base")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n SomeCustomProperty "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("?.")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetBoolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SomeCustomProperty"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")])]),t._v(" SomeCustomProperty "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// binary serialization support")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetObjectData")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SerializationInfo")]),t._v(" info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StreamingContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("base")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetObjectData")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("?.")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddValue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SomeCustomProperty"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" SomeCustomProperty"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// JSON serialization support")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CustomCalendarSerializer")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CalendarSerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("CustomCalendar"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("CustomCalendar")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JObject")]),t._v(" source"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("CustomCalendar")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("SerializeFields")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JsonWriter")]),t._v(" writer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CustomCalendar")]),t._v(" calendar"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n writer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WritePropertyName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SomeCustomProperty"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n writer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteValue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("calendar"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("SomeCustomProperty"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("DeserializeFields")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CustomCalendar")]),t._v(" calendar"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JObject")]),t._v(" source"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n calendar"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("SomeCustomProperty "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" source"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SomeCustomProperty"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Value")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Configuring custom calendar serializer")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" config "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" SchedulerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nconfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsePersistentStore")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("store "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n store"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseJsonSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("json "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n json"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddCalendarSerializer")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("CustomCalendar"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("CustomCalendarSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// or just globally which is what above code calls")]),t._v("\nJsonObjectSerializer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddCalendarSerializer")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("CustomCalendar"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("CustomCalendarSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/106.8db45d2f.js b/assets/js/106.8db45d2f.js new file mode 100644 index 000000000..0b4c70fdc --- /dev/null +++ b/assets/js/106.8db45d2f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[106],{480:function(t,s,n){"use strict";n.r(s);var a=n(26),e=Object(a.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[n("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Extensions.DependencyInjection",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Extensions.DependencyInjection"),n("OutboundLink")],1),t._v("\nprovides integration with "),n("a",{attrs:{href:"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection",target:"_blank",rel:"noopener noreferrer"}},[t._v("Microsoft Dependency Injection"),n("OutboundLink")],1),t._v(".")]),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),n("p",[t._v("Quartz 3.1 or later required.")])]),t._v(" "),n("h2",{attrs:{id:"installation"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),n("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v("Install-Package Quartz.Extensions.DependencyInjection\n")])])]),n("h2",{attrs:{id:"using"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#using"}},[t._v("#")]),t._v(" Using")]),t._v(" "),n("p",[t._v("You can add Quartz configuration by invoking an extension method "),n("code",[t._v("AddQuartz")]),t._v(" on "),n("code",[t._v("IServiceCollection")]),t._v(".\nThe configuration building wraps various "),n("a",{attrs:{href:"../configuration/reference"}},[t._v("configuration properties")]),t._v(" with strongly-typed API.\nYou can also configure properties using standard .NET Core "),n("code",[t._v("appsettings.json")]),t._v(" inside configuration section "),n("code",[t._v("Quartz")]),t._v(".")]),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),n("p",[n("RouterLink",{attrs:{to:"/documentation/quartz-3.x/packages/hosted-services-integration.html"}},[t._v("Quartz.Extensions.Hosting")]),t._v(" allows you to have a background service for your application that handles starting and stopping the scheduler.")],1)]),t._v(" "),n("p",[n("strong",[t._v("Example appsettings.json")])]),t._v(" "),n("div",{staticClass:"language-json extra-class"},[n("pre",{pre:!0,attrs:{class:"language-json"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token property"}},[t._v('"Logging"')]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token property"}},[t._v('"LogLevel"')]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token property"}},[t._v('"Default"')]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Information"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token property"}},[t._v('"Microsoft"')]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Warning"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token property"}},[t._v('"Microsoft.Hosting.Lifetime"')]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Information"')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token property"}},[t._v('"Quartz"')]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token property"}},[t._v('"quartz.scheduler.instanceName"')]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Quartz ASP.NET Core Sample Scheduler"')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"di-aware-job-factories"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#di-aware-job-factories"}},[t._v("#")]),t._v(" DI aware job factories")]),t._v(" "),n("p",[t._v("Quartz comes with two built-in alternatives for job factory which can be configured via either calling "),n("code",[t._v("UseMicrosoftDependencyInjectionJobFactory")]),t._v(" or "),n("code",[t._v("UseMicrosoftDependencyInjectionScopedJobFactory")]),t._v(" (deprecated).")]),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),n("p",[t._v("As of Quartz.NET 3.3.2 all jobs produced by the default job factory are scoped jobs, you should no longer use "),n("code",[t._v("UseMicrosoftDependencyInjectionScopedJobFactory")]),t._v(".")])]),t._v(" "),n("h3",{attrs:{id:"job-instance-construction"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#job-instance-construction"}},[t._v("#")]),t._v(" Job instance construction")]),t._v(" "),n("p",[t._v("By default Quartz will try to resolve job's type from container and if there's no explicit registration Quartz will use "),n("code",[t._v("ActivatorUtilities")]),t._v(" to construct job and inject it's dependencies\nvia constructor. Job should have only one public constructor.")]),t._v(" "),n("h3",{attrs:{id:"persistent-job-stores"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#persistent-job-stores"}},[t._v("#")]),t._v(" Persistent job stores")]),t._v(" "),n("p",[t._v("The scheduling configuration will be checked against database and updated accordingly every time your application starts and schedule is being evaluated.")]),t._v(" "),n("div",{staticClass:"custom-block warning"},[n("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),n("p",[t._v("When using persistent job store, make sure you define job and trigger names for your scheduling so that existence checks work correctly against\nthe data you already have in your database.")]),t._v(" "),n("p",[t._v("Using API to configure triggers and jobs without explicit job identity configuration will cause jobs and triggers to have different generated name each time configuration is being evaluated.")]),t._v(" "),n("p",[t._v("With persistent job stores it's best practice to always declare at least job and trigger name. Omitting the group for them will produce same default group value for every invocation.")])]),t._v(" "),n("p",[n("strong",[t._v("Example Startup.ConfigureServices configuration")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token return-type class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ConfigureServices")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IServiceCollection")]),t._v(" services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// base configuration from appsettings.json")]),t._v("\n services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Configure")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("QuartzOptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Configuration"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetSection")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Quartz"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// if you are using persistent job store, you might want to alter some options")]),t._v("\n services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Configure")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("QuartzOptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Scheduling"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("IgnoreDuplicates "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// default: false")]),t._v("\n options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Scheduling"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("OverWriteExistingData "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// default: true")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartz")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("q "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// handy when part of cluster or you want to otherwise identify multiple schedulers")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("SchedulerId "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Scheduler-Core"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we take this from appsettings.json, just show it's possible")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// q.SchedulerName = "Quartz ASP.NET Core Sample Scheduler";')]),t._v("\n \n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// as of 3.3.2 this also injects scoped services (like EF DbContext) without problems")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseMicrosoftDependencyInjectionJobFactory")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// or for scoped service support like EF Core DbContext")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// q.UseMicrosoftDependencyInjectionScopedJobFactory();")]),t._v("\n \n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// these are the defaults")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseSimpleTypeLoader")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseInMemoryStore")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseDefaultThreadPool")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tp "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n tp"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MaxConcurrency "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// quickest way to create a job with single trigger is to use ScheduleJob")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// (requires version 3.2)")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" trigger\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Combined Configuration Trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("EvenSecondDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("7")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDailyTimeIntervalSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithInterval")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" IntervalUnit"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Second"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome trigger configured for a job with single call"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// you can also configure individual jobs and triggers with code")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this allows you to associated multiple triggers with same job")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// (if you want to have different job data map per trigger for example)")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJob")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("j "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" j\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StoreDurably")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we need to store durably if no trigger is associated")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome job"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// here's a known job for triggers")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" jobKey "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobKey")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"awesome job"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"awesome group"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJob")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" j "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" j\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome job"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTrigger")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("t "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" t\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Simple Trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithInterval")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeSpan"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome simple trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTrigger")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("t "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" t\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Cron Trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("EvenSecondDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0/3 * * * * ?"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome cron trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// you can add calendars too (requires version 3.2)")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" calendarName "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidayCalendar"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddCalendar")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HolidayCalendar"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token named-parameter punctuation"}},[t._v("name")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" calendarName"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token named-parameter punctuation"}},[t._v("replace")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token named-parameter punctuation"}},[t._v("updateTriggers")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddExcludedDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("DateTime")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("2020")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTrigger")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("t "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" t\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Daily Trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("EvenSecondDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDailyTimeIntervalSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithInterval")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" IntervalUnit"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Second"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome daily time interval trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ModifiedByCalendar")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("calendarName"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// also add XML configuration and poll it for changes")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseXmlSchedulingConfiguration")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Files "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"~/quartz_jobs.config"')]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ScanInterval "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TimeSpan"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FailOnFileNotFound "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FailOnSchedulingError "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// convert time zones using converter that can handle Windows/Linux differences")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseTimeZoneConverter")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// auto-interrupt long-running job")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseJobAutoInterrupt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this is the default")]),t._v("\n options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("DefaultMaxRunTime "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TimeSpan"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromMinutes")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SlowJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n triggerConfigurator "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" triggerConfigurator\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"slowJobTrigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n jobConfigurator "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" jobConfigurator\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"slowJob"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("JobInterruptMonitorPlugin"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMapKeyAutoInterruptable"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// allow only five seconds for this job, overriding default configuration")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("JobInterruptMonitorPlugin"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMapKeyMaxRunTime"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" TimeSpan"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TotalMilliseconds"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ToString")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CultureInfo"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("InvariantCulture"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// add some listeners")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSchedulerListener")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SampleSchedulerListener"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SampleJobListener"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("GroupMatcher"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("GroupEquals")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Group"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n q"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTriggerListener")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SampleTriggerListener"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// example of persistent job store using JSON serializer as an example")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('/*\n q.UsePersistentStore(s =>\n {\n s.UseProperties = true;\n s.RetryInterval = TimeSpan.FromSeconds(15);\n s.UseSqlServer(sqlServer =>\n {\n sqlServer.ConnectionString = "some connection string";\n // this is the default\n sqlServer.TablePrefix = "QRTZ_";\n });\n s.UseJsonSerializer();\n s.UseClustering(c =>\n {\n c.CheckinMisfireThreshold = TimeSpan.FromSeconds(20);\n c.CheckinInterval = TimeSpan.FromSeconds(10);\n });\n });\n */')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\n\t"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we can use options pattern to support hooking your own configuration")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// because we don't use service registration api, ")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we need to manually ensure the job is present in DI")]),t._v("\n\tservices"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTransient")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t\t\n\tservices"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Configure")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SampleOptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Configuration"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetSection")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sample"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tservices"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddOptions")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("QuartzOptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Configure")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("IOptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SampleOptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" dep"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("IsNullOrWhiteSpace")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dep"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Value"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CronSchedule"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),n("span",{pre:!0,attrs:{class:"token class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" jobKey "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobKey")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options-custom-job"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"custom"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t\toptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJob")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("j "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" j"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t\toptions"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTrigger")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" trigger\n\t\t\t\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options-custom-trigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"custom"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dep"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Value"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CronSchedule"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\t\n\t\t\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Quartz.Extensions.Hosting allows you to fire background service that handles scheduler lifecycle")]),t._v("\n services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartzHostedService")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// when shutting down we want jobs to complete gracefully")]),t._v("\n options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("WaitForJobsToComplete "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/107.7ec33075.js b/assets/js/107.7ec33075.js new file mode 100644 index 000000000..98b02d4a6 --- /dev/null +++ b/assets/js/107.7ec33075.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[107],{481:function(t,e,a){"use strict";a.r(e);var n=a(26),s=Object(n.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.OpenTelemetry.Instrumentation",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.OpenTelemetry.Instrumentation"),a("OutboundLink")],1),t._v("\nprovides integration with "),a("a",{attrs:{href:"https://opentelemetry.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("OpenTelemetry"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("Quartz 3.1 or later required.")])]),t._v(" "),a("div",{staticClass:"custom-block danger"},[a("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),a("p",[t._v("The integration library can still live a bit and thus integration API can have breaking changes and change behavior.")])]),t._v(" "),a("h2",{attrs:{id:"installation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),a("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[t._v("Install-Package Quartz.OpenTelemetry.Instrumentation\n")])])]),a("p",[t._v("It also makes sense to install package for exporter to actually get the results somewhere.")]),t._v(" "),a("h2",{attrs:{id:"using"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using"}},[t._v("#")]),t._v(" Using")]),t._v(" "),a("p",[t._v("You can add Quartz configuration by invoking an extension method "),a("code",[t._v("AddQuartzInstrumentation")]),t._v(" on "),a("code",[t._v("TracerProviderBuilder")]),t._v(".")]),t._v(" "),a("p",[t._v("In the next example we will integrate with "),a("a",{attrs:{href:"https://www.jaegertracing.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Jaeger"),a("OutboundLink")],1),t._v(". We expect that you have also installed dependencies:")]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://www.nuget.org/packages/OpenTelemetry.Extensions.Hosting",target:"_blank",rel:"noopener noreferrer"}},[t._v("OpenTelemetry.Extensions.Hosting"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"https://www.nuget.org/packages/OpenTelemetry.Exporter.Jaeger",target:"_blank",rel:"noopener noreferrer"}},[t._v("OpenTelemetry.Exporter.Jaeger"),a("OutboundLink")],1)])]),t._v(" "),a("p",[t._v("You can run local Jaeger via docker using:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("$ docker run -d --name jaeger \\\n -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \\\n -p 5775:5775/udp \\\n -p 6831:6831/udp \\\n -p 6832:6832/udp \\\n -p 5778:5778 \\\n -p 16686:16686 \\\n -p 14268:14268 \\\n -p 14250:14250 \\\n -p 9411:9411 \\\n jaegertracing/all-in-one:1.18\n")])])]),a("p",[a("strong",[t._v("Example Startup.ConfigureServices configuration")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ConfigureServices")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IServiceCollection")]),t._v(" services"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// make sure you configure logging and open telemetry before quartz services")]),t._v("\n\n services"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddOpenTelemetry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("builder "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n builder\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartzInstrumentation")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseJaegerExporter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("o "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n o"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ServiceName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"My Software Name"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// these are the defaults")]),t._v("\n o"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("AgentHost "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"localhost"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n o"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("AgentPort "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6831")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/108.428f64db.js b/assets/js/108.428f64db.js new file mode 100644 index 000000000..da1420884 --- /dev/null +++ b/assets/js/108.428f64db.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[108],{482:function(t,a,n){"use strict";n.r(a);var e=n(26),s=Object(e.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[n("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.OpenTracing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.OpenTracing"),n("OutboundLink")],1),t._v("\nprovides integration with "),n("a",{attrs:{href:"https://opentracing.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("OpenTracing"),n("OutboundLink")],1),t._v(". You may also consider\n"),n("RouterLink",{attrs:{to:"/documentation/quartz-3.x/packages/opentelemetry-integration.html"}},[t._v("Quartz.OpenTelemetry.Instrumentation")]),t._v(" package which will supercede OpenTracing and OpenCensus\nwhen OpenTelemetry project reaches maturity.")],1),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),n("p",[t._v("Quartz 3.2.3 or later required.")])]),t._v(" "),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),n("p",[t._v("The integration library can still live a bit and thus integration API can have breaking changes and change behavior.")])]),t._v(" "),n("h2",{attrs:{id:"installation"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),n("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v("Install-Package Quartz.OpenTracing\n")])])]),n("h2",{attrs:{id:"using"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#using"}},[t._v("#")]),t._v(" Using")]),t._v(" "),n("p",[t._v("You can add Quartz configuration by invoking an extension method "),n("code",[t._v("AddQuartzOpenTracing")]),t._v(" on "),n("code",[t._v("IServiceCollection")]),t._v(".")]),t._v(" "),n("p",[n("strong",[t._v("Example Startup.ConfigureServices configuration")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token return-type class-name"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ConfigureServices")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IServiceCollection")]),t._v(" services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// make sure you configure logging and OpenTracing before quartz services")]),t._v("\n services"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartzOpenTracing")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// these are the defaults")]),t._v("\n options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ComponentName "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Quartz"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n options"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("IncludeExceptionDetails "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/109.60b57a1e.js b/assets/js/109.60b57a1e.js new file mode 100644 index 000000000..058dbbaec --- /dev/null +++ b/assets/js/109.60b57a1e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[109],{483:function(t,a,e){"use strict";e.r(a);var s=e(26),n=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("p",[e("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Jobs",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Jobs"),e("OutboundLink")],1),t._v(" provides some useful ready-made jobs for your convenience.")]),t._v(" "),e("h2",{attrs:{id:"installation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),e("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",[e("code",[t._v("Install-Package Quartz.Jobs\n")])])]),e("h2",{attrs:{id:"features"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#features"}},[t._v("#")]),t._v(" Features")]),t._v(" "),e("h3",{attrs:{id:"directoryscanjob"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#directoryscanjob"}},[t._v("#")]),t._v(" DirectoryScanJob")]),t._v(" "),e("p",[t._v('Inspects a directory and compares whether any files\' "last modified dates" have changed since the last time it was inspected.\nIf one or more files have been updated (or created), the job invokes a "call-back" method on an '),e("code",[t._v("IDirectoryScanListener")]),t._v("that can be found in the "),e("code",[t._v("SchedulerContext")]),t._v(".")]),t._v(" "),e("h3",{attrs:{id:"filescanjob"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#filescanjob"}},[t._v("#")]),t._v(" FileScanJob")]),t._v(" "),e("p",[t._v('Inspects a file and compares whether its "last modified dates" have changed since the last time it was inspected.\nIf one or more files have been updated (or created), the job invokes a "call-back" method on an '),e("code",[t._v("IFileScanListener")]),t._v("that can be found in the "),e("code",[t._v("SchedulerContext")]),t._v(".")]),t._v(" "),e("h3",{attrs:{id:"nativejob"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#nativejob"}},[t._v("#")]),t._v(" NativeJob")]),t._v(" "),e("p",[t._v("Built in job for executing native executables in a separate process.")]),t._v(" "),e("p",[e("strong",[t._v("Example")]),t._v("*")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" job "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobDetail")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dumbJob"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token type-expression class-name"}},[t._v("Quartz"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Jobs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("NativeJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\njob"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMap"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Put")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Quartz"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Jobs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("NativeJob"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PropertyCommand"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"echo \\"hi\\" >> foobar.txt"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token class-name"}},[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" trigger "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("MakeSecondlyTrigger")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\ntrigger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dumbTrigger"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("p",[t._v("If PropertyWaitForProcess is true, then the integer exit value of the process will be saved as the job execution result in the "),e("code",[t._v("JobExecutionContext")]),t._v(".")]),t._v(" "),e("h3",{attrs:{id:"sendmailjob"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#sendmailjob"}},[t._v("#")]),t._v(" SendMailJob")]),t._v(" "),e("p",[t._v("A Job which sends an e-mail with the configured content to the configured recipient.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/11.e2aadbde.js b/assets/js/11.e2aadbde.js new file mode 100644 index 000000000..685c10ff6 --- /dev/null +++ b/assets/js/11.e2aadbde.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{522:function(n,t,e){"use strict";e.r(t);var i=e(26),o=Object(i.a)({},(function(){var n=this.$createElement,t=this._self._c||n;return t("div",[t("router-link",{attrs:{to:"/download"}},[this._v("See download and installation instructions")]),this._v(".\n")],1)}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/110.ee5b642d.js b/assets/js/110.ee5b642d.js new file mode 100644 index 000000000..488118adc --- /dev/null +++ b/assets/js/110.ee5b642d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[110],{484:function(t,n,a){"use strict";a.r(n);var s=a(26),e=Object(s.a)({},(function(){var t=this,n=t.$createElement,a=t._self._c||n;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Plugins",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Plugins"),a("OutboundLink")],1),t._v(" provides some useful ready-mady plugins for your convenience.")]),t._v(" "),a("h2",{attrs:{id:"installation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),a("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[t._v("Install-Package Quartz.Plugins\n")])])]),a("h2",{attrs:{id:"configuration"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[t._v("#")]),t._v(" Configuration")]),t._v(" "),a("p",[t._v("Plugins are configured by using either DI configuration extensions or adding required configuration keys.")]),t._v(" "),a("p",[t._v("Configuration key in in format "),a("code",[t._v("quartz.plgin.{name-to-refer-with}.{property}")]),t._v(".")]),t._v(" "),a("p",[a("RouterLink",{attrs:{to:"/documentation/quartz-3.x/configuration/reference.html#plug-ins"}},[t._v("See configuration reference")]),t._v(" on how to configure each plugin")],1),t._v(" "),a("h2",{attrs:{id:"features"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#features"}},[t._v("#")]),t._v(" Features")]),t._v(" "),a("h3",{attrs:{id:"loggingjobhistoryplugin"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#loggingjobhistoryplugin"}},[t._v("#")]),t._v(" LoggingJobHistoryPlugin")]),t._v(" "),a("p",[t._v("Logs a history of all job executions (and execution vetoes) and writes the entries to configured logging infrastructure.")]),t._v(" "),a("h3",{attrs:{id:"shutdownhookplugin"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#shutdownhookplugin"}},[t._v("#")]),t._v(" ShutdownHookPlugin")]),t._v(" "),a("p",[t._v("This plugin catches the event of the VM terminating (such as upon a CRTL-C) and tells the scheduler to Shutdown.")]),t._v(" "),a("h3",{attrs:{id:"xmlschedulingdataprocessorplugin"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#xmlschedulingdataprocessorplugin"}},[t._v("#")]),t._v(" XMLSchedulingDataProcessorPlugin")]),t._v(" "),a("p",[t._v("This plugin loads XML file(s) to add jobs and schedule them with triggers as the scheduler is initialized, and can optionally periodically scan thefile for changes.")]),t._v(" "),a("div",{staticClass:"custom-block warning"},[a("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),a("p",[t._v("The periodically scanning of files for changes is not currently supported in a clustered environment.")])]),t._v(" "),a("h3",{attrs:{id:"jobinterruptmonitorplugin"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobinterruptmonitorplugin"}},[t._v("#")]),t._v(" JobInterruptMonitorPlugin")]),t._v(" "),a("p",[t._v('This plugin catches the event of job running for a long time (more than the configured max time) and tells the scheduler to "try" interrupting it if enabled.')]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("Quartz 3.3 or later required.")])]),t._v(" "),a("p",[t._v("Each job configuration needs to have "),a("code",[t._v("JobInterruptMonitorPlugin.JobDataMapKeyAutoInterruptable")]),t._v(" key's value set to true in order for plugin to monitor the execution timeout.\nJobs can also define custom timeout value instead of global default by using key "),a("code",[t._v("JobInterruptMonitorPlugin.JobDataMapKeyMaxRunTime")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" job "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SlowJob"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"slowJob"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("JobInterruptMonitorPlugin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMapKeyAutoInterruptable"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// allow only five seconds for this job, overriding default configuration")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("JobInterruptMonitorPlugin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMapKeyMaxRunTime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" TimeSpan"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TotalMilliseconds"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ToString")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CultureInfo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("InvariantCulture"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/111.5ea56c24.js b/assets/js/111.5ea56c24.js new file mode 100644 index 000000000..2b686c215 --- /dev/null +++ b/assets/js/111.5ea56c24.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[111],{485:function(t,s,a){"use strict";a.r(s);var e=a(26),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Plugins.TimeZoneConverter",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Plugins.TimeZoneConverter"),a("OutboundLink")],1),t._v("\nprovides integration with "),a("a",{attrs:{href:"https://github.com/mj1856/TimeZoneConverter",target:"_blank",rel:"noopener noreferrer"}},[t._v("TimeZoneConverter"),a("OutboundLink")],1),t._v(" which helps to bridge between\n*nix and Windows differences.")]),t._v(" "),a("h2",{attrs:{id:"installation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),a("p",[t._v("You need to add NuGet package reference to your project which uses Quartz.")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[t._v("Install-Package Quartz.Plugins.TimeZoneConverter\n")])])]),a("h2",{attrs:{id:"using"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using"}},[t._v("#")]),t._v(" Using")]),t._v(" "),a("p",[a("strong",[t._v("Classic property-based configuration")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" properties "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NameValueCollection")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"quartz.plugin.timeZoneConverter.type"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Quartz.Plugin.TimeZoneConverter.TimeZoneConverterPlugin, Quartz.Plugins.TimeZoneConverter"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" schedulerFactory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("properties"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Configuring using scheduler builder")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" config "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" SchedulerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseTimeZoneConverter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" schedulerFactory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/112.f9b9113a.js b/assets/js/112.f9b9113a.js new file mode 100644 index 000000000..2642de176 --- /dev/null +++ b/assets/js/112.f9b9113a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[112],{486:function(t,s,a){"use strict";a.r(s);var n=a(26),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("Welcome to the Quick Start Guide for Quartz.NET. As you read this guide, expect to see details of:")]),t._v(" "),a("ul",[a("li",[t._v("Downloading Quartz.NET")]),t._v(" "),a("li",[t._v("Installing Quartz.NET")]),t._v(" "),a("li",[t._v("Configuring Quartz to your own particular needs")]),t._v(" "),a("li",[t._v("Starting a sample application")])]),t._v(" "),a("h2",{attrs:{id:"download-and-install"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#download-and-install"}},[t._v("#")]),t._v(" Download and Install")]),t._v(" "),a("p",[t._v("You can either download the zip file or use the NuGet package.\nNuGet package contains only the binaries needed to run Quartz.NET, zip file comes with source code, samples and Quartz.NET server sample application.")]),t._v(" "),a("h2",{attrs:{id:"nuget-package"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#nuget-package"}},[t._v("#")]),t._v(" NuGet Package")]),t._v(" "),a("p",[t._v("Couldn't get any simpler than this. Just fire up Visual Studio (with NuGet installed) and add reference to package "),a("strong",[t._v("Quartz")]),t._v(" from package manager extension:")]),t._v(" "),a("ul",[a("li",[t._v("Right-click on your project's References and choose "),a("strong",[t._v("Manage NuGet Packages...")])]),t._v(" "),a("li",[t._v("Choose "),a("strong",[t._v("Online")]),t._v(" category from the left")]),t._v(" "),a("li",[t._v("Enter "),a("strong",[t._v("Quartz")]),t._v(" to the top right search and hit enter")]),t._v(" "),a("li",[t._v("Choose "),a("strong",[t._v("Quartz.NET")]),t._v(" from search results and hit install")]),t._v(" "),a("li",[t._v("Done!")])]),t._v(" "),a("p",[t._v("or from NuGet Command-Line:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[t._v("Install-Package Quartz\n")])])]),a("p",[t._v("If you want to add JSON Serialization, just add the "),a("a",{attrs:{href:"packages/json-serialization"}},[t._v("Quartz.Serialization.Json")]),t._v(" package the same way.")]),t._v(" "),a("h3",{attrs:{id:"zip-archive"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#zip-archive"}},[t._v("#")]),t._v(" Zip Archive")]),t._v(" "),a("p",[a("strong",[t._v("Short version")]),t._v(": Once you've downloaded Quartz.NET, unzip it somewhere, grab the "),a("code",[t._v("Quartz.dll")]),t._v(" from bin directory and start to use it.")]),t._v(" "),a("p",[t._v("Quartz core library does not have any hard binary dependencies. You can opt-in to more dependencies when you choose to use JSON serialization package, which requires JSON.NET.\nYou need to have at least "),a("code",[t._v("Quartz.dll")]),t._v(" beside your app binaries to successfully run Quartz.NET. So just add it as a references to your Visual Studio project that uses them.\nYou can find these dlls from extracted archive from path "),a("strong",[t._v("bin\\your-target-framework-version\\release\\Quartz")]),t._v(".")]),t._v(" "),a("h2",{attrs:{id:"configuration"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[t._v("#")]),t._v(" Configuration")]),t._v(" "),a("p",[t._v("This is the big bit! Quartz.NET is a very configurable library. There are two main ways (which are not mutually exclusive) to supply Quartz.NET configuration information:")]),t._v(" "),a("h3",{attrs:{id:"fluent-scheduler-builder-api"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#fluent-scheduler-builder-api"}},[t._v("#")]),t._v(" Fluent Scheduler Builder API")]),t._v(" "),a("p",[t._v("You can configure scheduler using C# fluent API, or via providing "),a("code",[t._v("NameValueCollection")]),t._v(" parameter to scheduler factory\nwhich contains configuration keys and values.")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// you can have base properties")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" properties "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NameValueCollection")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and override values via builder")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" scheduler "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" SchedulerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("properties"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// default max concurrency is 10")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseDefaultThreadPool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MaxConcurrency "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this is the default ")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .WithMisfireThreshold(TimeSpan.FromSeconds(60))")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsePersistentStore")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// force job data map values to be considered as strings")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// prevents nasty surprises if object is accidentally serialized and then ")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// serialization format breaks, defaults to false")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UseProperties "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseClustering")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// there are other SQL providers supported too ")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseSqlServer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my connection string"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this requires Quartz.Serialization.Json NuGet package")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseJsonSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// job initialization plugin handles our xml reading, without it defaults are used")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// requires Quartz.Plugins NuGet package")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseXmlSchedulingConfiguration")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Files "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"~/quartz_jobs.xml"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this is the default")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FailOnFileNotFound "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this is not the default")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FailOnSchedulingError "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("BuildScheduler")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h3",{attrs:{id:"configuration-files"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#configuration-files"}},[t._v("#")]),t._v(" Configuration files")]),t._v(" "),a("p",[t._v("Following files are searched for known configuration properties:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("YourApplication.exe.config")]),t._v(" configuration file using quartz-element (full .NET framework only)")]),t._v(" "),a("li",[a("code",[t._v("appsettings.json")]),t._v(" (.NET Core/NET5 onwards)")]),t._v(" "),a("li",[a("code",[t._v("quartz.config")]),t._v(" file in your application's root directory (works both with .NET Core and full .NET Framework)")])]),t._v(" "),a("p",[t._v("Full documentation of available properties is available in the "),a("a",{attrs:{href:"configuration/reference"}},[t._v("Quartz Configuration Reference")]),t._v(".")]),t._v(" "),a("p",[t._v("To get up and running quickly, a basic quartz.config looks something like this:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[t._v("quartz.scheduler.instanceName = MyScheduler\nquartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz\nquartz.threadPool.maxConcurrency = 3\n")])])]),a("p",[t._v("Remember to set the "),a("strong",[t._v("Copy to Output Directory")]),t._v(" on Visual Studio's file property pages to have value "),a("strong",[t._v("Copy always")]),t._v(". Otherwise the config will not be seen if it's not in build directory.")]),t._v(" "),a("p",[t._v("The scheduler created by this configuration has the following characteristics:")]),t._v(" "),a("ul",[a("li",[a("p",[a("code",[t._v("quartz.scheduler.instanceName")]),t._v(' - This scheduler\'s name will be "MyScheduler".')])]),t._v(" "),a("li",[a("p",[a("code",[t._v("quartz.threadPool.maxConcurrency")]),t._v(" - Maximum of 3 jobs can be run simultaneously (default is 10).")])]),t._v(" "),a("li",[a("p",[a("code",[t._v("quartz.jobStore.type")]),t._v(" - All of Quartz's data, such as details of jobs and triggers, is held in memory (rather than in a database).")])]),t._v(" "),a("li",[a("p",[t._v("Even if you have a database and want to use it with Quartz, I suggest you get Quartz working with the RamJobStore before you open up a whole new dimension by working with a database.")])])]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("Actually you don't need to define these properties if you don't want to, Quartz.NET comes with sane defaults")])]),t._v(" "),a("h2",{attrs:{id:"starting-a-sample-application"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#starting-a-sample-application"}},[t._v("#")]),t._v(" Starting a Sample Application")]),t._v(" "),a("p",[t._v("Now you've downloaded and installed Quartz, it's time to get a sample application up and running. The following code obtains an instance of the scheduler, starts it, then shuts it down:")]),t._v(" "),a("p",[a("strong",[t._v("Program.cs")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Threading"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Tasks")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Impl")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("namespace")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("QuartzSampleApp")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Program")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" args"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Grab the Scheduler instance from the Factory")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StdSchedulerFactory")]),t._v(" factory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" scheduler "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" factory"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetScheduler")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and start it off")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// some sleep to show what's happening")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Task"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Delay")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeSpan"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and last shut down the scheduler when you are ready to close your program")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Shutdown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("As of Quartz 3.0 your application will terminate when there's no code left to execute after "),a("code",[t._v("scheduler.Shutdown()")]),t._v(", because there won't be any active threads. You should manually block exiting of application if you want scheduler to keep running also after the Task.Delay and Shutdown has been processed.")]),t._v(" "),a("p",[t._v("Now running the program will not show anything. When 10 seconds have passed the program will just terminate. Lets add some logging to console.")]),t._v(" "),a("h2",{attrs:{id:"adding-logging"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#adding-logging"}},[t._v("#")]),t._v(" Adding logging")]),t._v(" "),a("p",[a("a",{attrs:{href:"https://github.com/damianh/LibLog/wiki",target:"_blank",rel:"noopener noreferrer"}},[t._v("LibLog"),a("OutboundLink")],1),t._v(" can be configured to use different logging frameworks under the hood; namely Log4Net, NLog and Serilog.")]),t._v(" "),a("p",[t._v("When LibLog does not detect any other logging framework to be present, it will be silent. We can configure a custom logger provider that just logs to console show the output\nif you don't have logging framework setup ready yet.")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("LogProvider"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("SetCurrentLogProvider")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("ConsoleLogProvider")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConsoleLogProvider")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ILogProvider")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Logger")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetLogger")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" exception"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" parameters"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" LogLevel"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Info "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" func "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Console"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"["')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" DateTime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ToLongTimeString")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"] ["')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" level "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"] "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("func")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" parameters"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("IDisposable")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("OpenNestedContext")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" message"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NotImplementedException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("IDisposable")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("OpenMappedContext")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("value")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")])]),t._v(" destructure "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NotImplementedException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h2",{attrs:{id:"trying-out-the-application-and-adding-jobs"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#trying-out-the-application-and-adding-jobs"}},[t._v("#")]),t._v(" Trying out the application and adding jobs")]),t._v(" "),a("p",[t._v("Now we should get a lot more information when we start the application.")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("[12.51.10] [Info] Quartz.NET properties loaded from configuration file 'C:\\QuartzSampleApp\\quartz.config'\n[12.51.10] [Info] Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl\n[12.51.10] [Info] Quartz Scheduler created\n[12.51.10] [Info] RAMJobStore initialized.\n[12.51.10] [Info] Scheduler meta-data: Quartz Scheduler (v3.0.0.0) 'MyScheduler' with instanceId 'NON_CLUSTERED'\n Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.\n NOT STARTED.\n Currently in standby mode.\n Number of jobs executed: 0\n Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 3 threads.\n Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.\n\n[12.51.10] [Info] Quartz scheduler 'MyScheduler' initialized\n[12.51.10] [Info] Quartz scheduler version: 3.0.0.0\n[12.51.10] [Info] Scheduler MyScheduler_$_NON_CLUSTERED started.\n")])])]),a("p",[t._v("We need a simple test job to test the functionality, lets create HelloJob that outputs greetings to console.")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HelloJob")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Console"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Out"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLineAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Greetings from HelloJob!"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("To do something interesting, you need code just after Start() method, before the Task.Delay.")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"job1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then repeat every 10 seconds")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Tell quartz to schedule the job using our trigger")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You could also schedule multiple triggers for the same job with")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// await scheduler.ScheduleJob(job, new List() { trigger1, trigger2 }, replace: true);")]),t._v("\n")])])]),a("p",[t._v("The complete console application will now look like this")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Threading"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Tasks")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Impl")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Logging")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("namespace")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("QuartzSampleApp")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Program")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" args"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n LogProvider"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("SetCurrentLogProvider")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("ConsoleLogProvider")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Grab the Scheduler instance from the Factory")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StdSchedulerFactory")]),t._v(" factory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" scheduler "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" factory"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetScheduler")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and start it off")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"job1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then repeat every 10 seconds")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Tell quartz to schedule the job using our trigger")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// some sleep to show what's happening")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Task"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Delay")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeSpan"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and last shut down the scheduler when you are ready to close your program")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Shutdown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n Console"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Press any key to close the application"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n Console"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ReadKey")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// simple log provider to get something to the console")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConsoleLogProvider")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ILogProvider")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Logger")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetLogger")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" exception"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" parameters"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" LogLevel"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Info "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" func "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Console"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"["')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" DateTime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ToLongTimeString")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"] ["')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" level "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"] "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("func")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" parameters"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("IDisposable")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("OpenNestedContext")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" message"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NotImplementedException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("IDisposable")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("OpenMappedContext")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("value")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")])]),t._v(" destructure "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("NotImplementedException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HelloJob")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Console"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Out"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLineAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Greetings from HelloJob!"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Now go have some fun exploring Quartz.NET! You can continue by reading "),a("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/index.html"}},[t._v("the tutorial")]),t._v(".")],1)])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/113.50eb57e0.js b/assets/js/113.50eb57e0.js new file mode 100644 index 000000000..701f300cf --- /dev/null +++ b/assets/js/113.50eb57e0.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[113],{487:function(t,e,o){"use strict";o.r(e);var r=o(26),s=Object(r.a)({},(function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[o("ApplicableVersion"),t._v(" "),o("ul",[o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/using-quartz.html"}},[t._v("Lesson 1: Using Quartz")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/jobs-and-triggers.html"}},[t._v("Lesson 2: Jobs And Triggers")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/more-about-jobs.html"}},[t._v("Lesson 3: More About Jobs & JobDetails")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/more-about-triggers.html"}},[t._v("Lesson 4: More About Triggers")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/simpletriggers.html"}},[t._v("Lesson 5: SimpleTriggers")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/crontriggers.html"}},[t._v("Lesson 6: CronTriggers")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/trigger-and-job-listeners.html"}},[t._v("Lesson 7: TriggerListeners & JobListeners")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/scheduler-listeners.html"}},[t._v("Lesson 8: SchedulerListeners")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/job-stores.html"}},[t._v("Lesson 9: JobStores")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/configuration-resource-usage-and-scheduler-factory.html"}},[t._v("Lesson 10: Configuration, Resource Usage and SchedulerFactory")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/advanced-enterprise-features.html"}},[t._v("Lesson 11: Advanced (Enterprise) Features")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/miscellaneous-features.html"}},[t._v("Lesson 12: Miscellaneous Features")])],1)])],1)}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/114.5a891d47.js b/assets/js/114.5a891d47.js new file mode 100644 index 000000000..97703901d --- /dev/null +++ b/assets/js/114.5a891d47.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[114],{488:function(e,t,s){"use strict";s.r(t);var n=s(26),r=Object(n.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("h2",{attrs:{id:"clustering"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#clustering"}},[e._v("#")]),e._v(" Clustering")]),e._v(" "),s("p",[e._v("Clustering currently only works with the AdoJobstore ("),s("code",[e._v("JobStoreTX")]),e._v(').\nFeatures include load-balancing and job fail-over (if the JobDetail\'s "request recovery" flag is set to true).')]),e._v(" "),s("p",[e._v("Enable clustering by setting the "),s("code",[e._v("quartz.jobStore.clustered")]),e._v(' property to "true".\nEach instance in the cluster should use the same copy of the quartz properties.\nExceptions of this would be to use properties that are identical, with the following allowable exceptions:\nDifferent thread pool size, and different value for the '),s("code",[e._v("quartz.scheduler.instanceId")]),e._v(" property.\nEach node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing "),s("code",[e._v("AUTO")]),e._v(" as the value of this property.")]),e._v(" "),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),s("p",[e._v("Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly (the clocks must be within a second of each other).\nSee "),s("a",{attrs:{href:"https://www.nist.gov/pml/time-and-frequency-division/services/internet-time-service-its",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://www.nist.gov/pml/time-and-frequency-division/services/internet-time-service-its"),s("OutboundLink")],1),e._v(" if you are unfamiliar with how to do this.")])]),e._v(" "),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),s("p",[e._v("Never start ("),s("code",[e._v("scheduler.Start()")]),e._v(") a non-clustered instance against the same set of database tables that any other instance is running ("),s("code",[e._v("Start()")]),e._v("ed) against.\nYou may get serious data corruption, and will definitely experience erratic behavior.")])]),e._v(" "),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),s("p",[e._v("Monitor and ensure that your nodes have enough CPU resources to complete jobs.\nWhen some nodes are in 100% CPU, they may be unable to update the job store and other nodes can consider these jobs lost and recover them by re-running.")])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/115.503308f5.js b/assets/js/115.503308f5.js new file mode 100644 index 000000000..7fe18021c --- /dev/null +++ b/assets/js/115.503308f5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[115],{489:function(t,e,a){"use strict";a.r(e);var o=a(26),n=Object(o.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v('Quartz is architected in modular way, and therefore to get it running, several components need to be "snapped" together.\nFortunately, some helpers exist for making this happen.')]),t._v(" "),a("p",[t._v("The major components that need to be configured before Quartz can do its work are:")]),t._v(" "),a("ul",[a("li",[t._v("ThreadPool")]),t._v(" "),a("li",[t._v("JobStore")]),t._v(" "),a("li",[t._v("DataSources (if necessary)")]),t._v(" "),a("li",[t._v("The Scheduler itself")])]),t._v(" "),a("p",[t._v("Thread pooling has changed a lot since the Task-based jobs were introduced.\nNow the default implementation, "),a("code",[t._v("DefaultThreadPool")]),t._v(" uses "),a("a",{attrs:{href:"https://docs.microsoft.com/en-us/dotnet/standard/threading/the-managed-thread-pool",target:"_blank",rel:"noopener noreferrer"}},[t._v("CLR's managed thread pool"),a("OutboundLink")],1),t._v(" to execute jobs as tasks.\nYou can configure the pool that have max concurrency, which effectively limits how many concurrent tasks can be scheduled to the CLR's thread pool.\nSee configuration reference for more details on how to configure the thread pool implementation.")]),t._v(" "),a("p",[t._v("JobStores and DataSources were discussed in Lesson 9 of this tutorial. Worth noting here, is the fact that all JobStores\nimplement the "),a("code",[t._v("IJobStore")]),t._v(" interface - and that if one of the bundled JobStores does not fit your needs, then you can make your own.")]),t._v(" "),a("p",[t._v("Finally, you need to create your Scheduler instance. The Scheduler itself needs to be given a name and handed\ninstances of a JobStore and ThreadPool.")]),t._v(" "),a("h2",{attrs:{id:"stdschedulerfactory"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#stdschedulerfactory"}},[t._v("#")]),t._v(" StdSchedulerFactory")]),t._v(" "),a("p",[a("code",[t._v("StdSchedulerFactory")]),t._v(" is an implementation of the "),a("code",[t._v("ISchedulerFactory")]),t._v(" interface.\nIt uses a set of properties ("),a("code",[t._v("NameValueCollection")]),t._v(") to create and initialize a Quartz Scheduler.\nThe properties are generally stored in and loaded from a file, but can also be created by your program and handed directly to the factory.\nSimply calling "),a("code",[t._v("GetScheduler()")]),t._v(" on the factory will produce the scheduler, initialize it (and its ThreadPool, JobStore and DataSources),\nand return a handle to its public interface.")]),t._v(" "),a("p",[t._v('You can find complete documentation in the "Configuration Reference" section of the Quartz documentation.')]),t._v(" "),a("h2",{attrs:{id:"directschedulerfactory"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#directschedulerfactory"}},[t._v("#")]),t._v(" DirectSchedulerFactory")]),t._v(" "),a("p",[a("code",[t._v("DirectSchedulerFactory")]),t._v(" is another "),a("code",[t._v("ISchedulerFactory")]),t._v(" implementation. It is useful to those wishing to create their Scheduler\ninstance in a more programmatic way. Its use is generally discouraged for the following reasons:")]),t._v(" "),a("ul",[a("li",[t._v("It requires the user to have a greater understanding of what they're doing, and")]),t._v(" "),a("li",[t._v("it does not allow for declarative configuration - or in other words, you end up hard-coding all of the scheduler's settings.")])]),t._v(" "),a("h2",{attrs:{id:"logging"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#logging"}},[t._v("#")]),t._v(" Logging")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("As of Quartz.NET 3.1, you can configure "),a("a",{attrs:{href:"https://www.nuget.org/packages/Microsoft.Extensions.Logging.Abstractions/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Microsoft.Extensions.Logging.Abstractions"),a("OutboundLink")],1),t._v(" to be used instead of LibLog.")])]),t._v(" "),a("h3",{attrs:{id:"liblog"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#liblog"}},[t._v("#")]),t._v(" LibLog")]),t._v(" "),a("p",[t._v("Quartz.NET uses "),a("a",{attrs:{href:"https://github.com/damianh/LibLog"}},[t._v("LibLog library")]),t._v(' for all of its logging needs.\nQuartz does not produce much logging information - generally just some information during initialization, and\nthen only messages about serious problems while Jobs are executing. In order to "tune" the logging settings\n(such as the amount of output, and where the output goes), you need to actually configure your logging framework of choice as LibLog mostly delegates the work to\nmore full-fledged logging framework like log4net, serilog etc.')]),t._v(" "),a("p",[t._v("Please see "),a("a",{attrs:{href:"https://github.com/damianh/LibLog/wiki"}},[t._v("LibLog Wiki")]),t._v(" for more information.")]),t._v(" "),a("h3",{attrs:{id:"microsoft-extensions-logging-abstractions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#microsoft-extensions-logging-abstractions"}},[t._v("#")]),t._v(" Microsoft.Extensions.Logging.Abstractions")]),t._v(" "),a("p",[t._v("You can configure Microsoft.Extensions.Logging.Abstractions either manually or using services found in "),a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Extensions.DependencyInjection",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Extensions.DependencyInjection"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("h4",{attrs:{id:"manual-configuration"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#manual-configuration"}},[t._v("#")]),t._v(" Manual configuration")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// obtain your logger factory, for example from IServiceProvider")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ILoggerFactory")]),t._v(" loggerFactory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token range operator"}},[t._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Quartz 3.1")]),t._v("\nQuartz"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LogContext"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("SetCurrentLogProvider")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("loggerFactory"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Quartz 3.2 onwards")]),t._v("\nQuartz"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Logging"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LogContext"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("SetCurrentLogProvider")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("loggerFactory"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h4",{attrs:{id:"configuration-using-microsoft-di-integration"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#configuration-using-microsoft-di-integration"}},[t._v("#")]),t._v(" Configuration using Microsoft DI integration.")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("services"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddQuartz")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("q "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this automatically registers the Microsoft Logging")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/116.edf242c3.js b/assets/js/116.edf242c3.js new file mode 100644 index 000000000..1ae762e77 --- /dev/null +++ b/assets/js/116.edf242c3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[116],{490:function(t,e,a){"use strict";a.r(e);var i=a(26),n=Object(i.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"introduction"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),a("p",[t._v("cron is a UNIX tool that has been around for a long time, so its scheduling capabilities are powerful and proven.\nThe CronTrigger class is based on the scheduling capabilities of cron.")]),t._v(" "),a("p",[t._v('CronTrigger uses "cron expressions", which are able to create firing schedules such as: "At 8:00am every Monday through Friday" or "At 1:30am every last Friday of the month".')]),t._v(" "),a("p",[t._v("Cron expressions are powerful, but can be pretty confusing. This tutorial aims to take some of the mystery out of creating a cron expression,\ngiving users a resource which they can visit before having to ask in a forum or mailing list.")]),t._v(" "),a("h2",{attrs:{id:"format"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#format"}},[t._v("#")]),t._v(" Format")]),t._v(" "),a("p",[t._v("A cron expression is a string comprised of 6 or 7 fields separated by white space.\nFields can contain any of the allowed values, along with various combinations of the allowed special characters for that field. The fields are as follows:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",[a("strong",[t._v("Field Name")])]),t._v(" "),a("th",[a("strong",[t._v("Mandatory")])]),t._v(" "),a("th",[a("strong",[t._v("Allowed Values")])]),t._v(" "),a("th",[a("strong",[t._v("Allowed Special Characters")])])])]),t._v(" "),a("tbody",[a("tr",[a("td",[t._v("Seconds")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("0-59")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Minutes")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("0-59")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Hours")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("0-23")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Day of month")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("1-31")]),t._v(" "),a("td",[t._v(", - * ? / L W")])]),t._v(" "),a("tr",[a("td",[t._v("Month")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("1-12 or JAN-DEC")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Day of week")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("1-7 or SUN-SAT")]),t._v(" "),a("td",[t._v(", - * ? / L #")])]),t._v(" "),a("tr",[a("td",[t._v("Year")]),t._v(" "),a("td",[t._v("NO")]),t._v(" "),a("td",[t._v("empty, 1970-2099")]),t._v(" "),a("td",[t._v(", - * /")])])])]),t._v(" "),a("p",[t._v("So cron expressions can be as simple as this: "),a("code",[t._v("* * * * ? *")])]),t._v(" "),a("p",[t._v("or more complex, like this: "),a("code",[t._v("0/5 14,18,3-39,52 * ? JAN,MAR,SEP MON-FRI 2002-2010")])]),t._v(" "),a("h2",{attrs:{id:"special-characters"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#special-characters"}},[t._v("#")]),t._v(" Special characters")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("*")]),t._v(' ("all values") - used to select all values within a field. For example, '),a("code",[t._v("*")]),t._v(' in the minute field means "every minute".')]),t._v(" "),a("li",[a("code",[t._v("?")]),t._v(' ("no specific value") - useful when you need to specify something in one of the two fields in which the character is allowed, but not the other.\nFor example, if I want my trigger to fire on a particular day of the month (say, the 10th), but don\'t care what day of the week that happens to be,\nI would put '),a("code",[t._v("10")]),t._v(" in the day-of-month field, and "),a("code",[t._v("?")]),t._v(" in the day-of-week field. See the examples below for clarification.")]),t._v(" "),a("li",[a("code",[t._v("-")]),t._v(" - used to specify ranges. For example, "),a("code",[t._v("10-12")]),t._v(' in the hour field means "the hours 10, 11 and 12".')]),t._v(" "),a("li",[a("code",[t._v(",")]),t._v(" - used to specify additional values. For example, "),a("code",[t._v("MON,WED,FRI")]),t._v(' in the day-of-week field means "the days Monday, Wednesday, and Friday".')]),t._v(" "),a("li",[a("code",[t._v("/")]),t._v(" - used to specify increments. For example, "),a("code",[t._v("0/15")]),t._v(' in the seconds field means "the seconds 0, 15, 30, and 45".\nAnd '),a("code",[t._v("5/15")]),t._v(' in the seconds field means "the seconds 5, 20, 35, and 50".\nYou can also specify '),a("code",[t._v("/")]),t._v(" after the \"character - in this case\" is equivalent to having '0' before the '/'.\n"),a("code",[t._v("1/3")]),t._v(' in the day-of-month field means "fire every 3 days starting on the first day of the month".')]),t._v(" "),a("li",[a("code",[t._v("L")]),t._v(' ("last") - has different meaning in each of the two fields in which it is allowed.\nFor example, the value '),a("code",[t._v("L")]),t._v(' in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years.\nIf used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" -\nfor example '),a("code",[t._v("6L")]),t._v(' means "the last friday of the month". You can also specify an offset from the last day of the month, such as '),a("code",[t._v("L-3")]),t._v(" which\nwould mean the third-to-last day of the calendar month. When using the "),a("code",[t._v("L")]),t._v(" option, it is important not to specify lists, or ranges of values,\nas you'll get confusing/unexpected results.")]),t._v(" "),a("li",[a("code",[t._v("W")]),t._v(' ("weekday") - used to specify the weekday (Monday-Friday) nearest the given day.\nAs an example, if you were to specify '),a("code",[t._v("15W")]),t._v(' as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month".\nSo if the 15th is a Saturday, the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the 16th. If the 15th is a Tuesday,\nthen it will fire on Tuesday the 15th. However if you specify '),a("code",[t._v("1W")]),t._v(" as the value for day-of-month, and the 1st is a Saturday, the trigger will fire on Monday the 3rd,\nas it will not 'jump' over the boundary of a month's days. The "),a("code",[t._v("W")]),t._v(" character can only be specified when the day-of-month is a single day, not a range or list of days.")])]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("L")]),t._v(" and "),a("code",[t._v("W")]),t._v(" characters can also be combined in the day-of-month field to yield "),a("code",[t._v("LW")]),t._v(', which translates to *"last weekday of the month".')])]),t._v(" "),a("ul",[a("li",[a("code",[t._v("#")]),t._v(' - used to specify "the nth" XXX day of the month. For example, the value of '),a("code",[t._v("6#3")]),t._v(' in the day-of-week field means\n"the third Friday of the month" (day 6 = Friday and "#3" = the 3rd one in the month).\nOther examples: '),a("code",[t._v("2#1")]),t._v(" = the first Monday of the month and "),a("code",[t._v("4#5")]),t._v(" = the fifth Wednesday of the month.\nNote that if you specify "),a("code",[t._v("#5")]),t._v(" and there is not 5 of the given day-of-week in the month, then no firing will occur that month.")])]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("The legal characters and the names of months and days of the week are not case sensitive. MON is the same as mon.")])]),t._v(" "),a("h2",{attrs:{id:"examples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[t._v("#")]),t._v(" Examples")]),t._v(" "),a("p",[t._v("Here are some full examples:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",{staticStyle:{"text-align":"left"}},[a("strong",[t._v("Expression")])]),t._v(" "),a("th",{staticStyle:{"text-align":"left"}},[a("strong",[t._v("Meaning")])])])]),t._v(" "),a("tbody",[a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0 12 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 12pm (noon) every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * *")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 * * ? *")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 * * ?\t2005")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day during the year 2005")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 * 14 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every minute starting at 2pm and ending at 2:59pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0/5 14 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0/5 14,18 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0-5 14 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every minute starting at 2pm and ending at 2:05pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 10,44 14 ? 3 WED")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * MON-FRI")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 15 * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the 15th day of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 L * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the last day of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 L-2 * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the 2nd-to-last last day of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6L")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the last Friday of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6L")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the last Friday of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6L 2002-2005")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6#3")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the third Friday of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0 12 1/5 * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 12pm (noon) every 5 days every month, starting on the first day of the month.")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 11 11 11 11 ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every November 11th at 11:11am.")])])])]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("Pay attention to the effects of '?' and '*' in the day-of-week and day-of-month fields!")])]),t._v(" "),a("h2",{attrs:{id:"notes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#notes"}},[t._v("#")]),t._v(" Notes")]),t._v(" "),a("div",{staticClass:"custom-block warning"},[a("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),a("p",[t._v("Support for specifying both a day-of-week and a day-of-month value is not complete (you must currently use the '?' character in one of these fields).")])]),t._v(" "),a("div",{staticClass:"custom-block warning"},[a("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),a("p",[t._v('Be careful when setting fire times between the hours of the morning when "daylight savings" changes occur in your locale (for US locales, this would typically be the hour before and after 2:00 AM - because the time shift can cause a skip or a repeat depending on whether the time moves back or jumps forward. You may find this wikipedia entry helpful in determining the specifics to your locale:\n'),a("a",{attrs:{href:"https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world"),a("OutboundLink")],1)])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/117.87d68a22.js b/assets/js/117.87d68a22.js new file mode 100644 index 000000000..f9080b273 --- /dev/null +++ b/assets/js/117.87d68a22.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[117],{491:function(t,s,e){"use strict";e.r(s);var n=e(26),a=Object(n.a)({},(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("p",[t._v("CronTriggers are often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions,\nrather than on the exactly specified intervals of SimpleTrigger.")]),t._v(" "),e("p",[t._v('With CronTrigger, you can specify firing-schedules such as "every Friday at noon", or "every weekday and 9:30 am",\nor even "every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday".')]),t._v(" "),e("p",[t._v("Even so, like SimpleTrigger, CronTrigger has a startTime which specifies when the schedule is in force, and an (optional)\nendTime that specifies when the schedule should be discontinued.")]),t._v(" "),e("h3",{attrs:{id:"cron-expressions"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#cron-expressions"}},[t._v("#")]),t._v(" Cron Expressions")]),t._v(" "),e("p",[e("em",[t._v("Cron-Expressions")]),t._v(" are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up\nof seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:")]),t._v(" "),e("ul",[e("li",[e("ol",[e("li",[t._v("Seconds")])])]),t._v(" "),e("li",[e("ol",{attrs:{start:"2"}},[e("li",[t._v("Minutes")])])]),t._v(" "),e("li",[e("ol",{attrs:{start:"3"}},[e("li",[t._v("Hours")])])]),t._v(" "),e("li",[e("ol",{attrs:{start:"4"}},[e("li",[t._v("Day-of-Month")])])]),t._v(" "),e("li",[e("ol",{attrs:{start:"5"}},[e("li",[t._v("Month")])])]),t._v(" "),e("li",[e("ol",{attrs:{start:"6"}},[e("li",[t._v("Day-of-Week")])])]),t._v(" "),e("li",[e("ol",{attrs:{start:"7"}},[e("li",[t._v("Year (optional field)")])])])]),t._v(" "),e("p",[t._v("An example of a complete cron-expression is the string "),e("code",[t._v("0 0 12 ? * WED")]),t._v(' - which means "every Wednesday at 12:00 pm".')]),t._v(" "),e("p",[t._v('Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED")\nexample could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".')]),t._v(" "),e("p",[t._v("Wild-cards (the "),e("code",[t._v("*")]),t._v(' character) can be used to say "every" possible value of this field. Therefore the '),e("code",[t._v("*")]),t._v(' character in the\n"Month" field of the previous example simply means "every month". A '),e("code",[t._v("*")]),t._v(' in the Day-Of-Week field would obviously mean "every day of the week".')]),t._v(" "),e("p",[t._v("All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers\n0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful\nabout how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings\nJAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday)\nor by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.")]),t._v(" "),e("p",[t._v("The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes,\nstarting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour,\nstarting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.")]),t._v(" "),e("p",[t._v("The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify \"no specific value\".\nThis is useful when you need to specify something in one of the two fields, but not the other.\nSee the examples below (and CronTrigger API documentation) for clarification.")]),t._v(" "),e("p",[t._v('The \'L\' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last",\nbut it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means\n"the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself,\nit simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" -\nfor example "6L" or "FRIL" both mean "the last friday of the month". When using the \'L\' option, it is important not to specify lists,\nor ranges of values, as you\'ll get confusing results.')]),t._v(" "),e("p",[t._v('The \'W\' is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month".')]),t._v(" "),e("p",[t._v('The \'#\' is used to specify "the nth" XXX weekday of the month. For example, the value of "6#3" or "FRI#3" in the day-of-week field means "the third Friday of the month".')]),t._v(" "),e("h2",{attrs:{id:"example-cron-expressions"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#example-cron-expressions"}},[t._v("#")]),t._v(" Example Cron Expressions")]),t._v(" "),e("p",[t._v("Here are a few more examples of expressions and their meanings - you can find even more in the API documentation for CronTrigger")]),t._v(" "),e("p",[e("strong",[t._v("CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",[e("code",[t._v('"0 0/5 * * * ?"\n')])])]),e("p",[e("strong",[t._v("CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",[e("code",[t._v('"10 0/5 * * * ?"\n')])])]),e("p",[e("strong",[t._v("CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",[e("code",[t._v('"0 30 10-13 ? * WED,FRI"\n')])])]),e("p",[e("strong",[t._v("CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month.\nNote that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",[e("code",[t._v('"0 0/30 8-9 5,20 * ?"\n')])])]),e("p",[t._v('Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am,\nand every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.')]),t._v(" "),e("h2",{attrs:{id:"building-crontriggers"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#building-crontriggers"}},[t._v("#")]),t._v(" Building CronTriggers")]),t._v(" "),e("p",[t._v("CronTrigger instances are built using "),e("code",[t._v("TriggerBuilder")]),t._v(" (for the trigger's main properties) and "),e("code",[t._v("WithCronSchedule")]),t._v("\nextension method (for the CronTrigger-specific properties).")]),t._v(" "),e("p",[t._v("You can also use "),e("code",[t._v("CronScheduleBuilder")]),t._v("'s static methods to create schedules.")]),t._v(" "),e("p",[e("strong",[t._v("Build a trigger that will fire every other minute, between 8am and 5pm, every day:")])]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 0/2 8-17 * * ?"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("p",[e("strong",[t._v("Build a trigger that will fire daily at 10:42 am:")])]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we use CronScheduleBuilder's static helper methods here")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("DailyAtHourAndMinute")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("p",[t._v("or -")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 42 10 * * ?"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("p",[e("strong",[t._v("Build a trigger that will fire on Wednesdays at 10:42 am, in a TimeZone other than the system's default:")])]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WeeklyOnDayAndHourAndMinute")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DayOfWeek"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Wednesday"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("InTimeZone")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeZoneInfo"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("FindSystemTimeZoneById")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Central America Standard Time"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("p",[t._v("or -")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 42 10 ? * WED"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" x "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("InTimeZone")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeZoneInfo"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("FindSystemTimeZoneById")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Central America Standard Time"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),e("h2",{attrs:{id:"crontrigger-misfire-instructions"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#crontrigger-misfire-instructions"}},[t._v("#")]),t._v(" CronTrigger Misfire Instructions")]),t._v(" "),e("p",[t._v("The following instructions can be used to inform Quartz what it should do when a misfire occurs for CronTrigger.\n(Misfire situations were introduced in the More About Triggers section of this tutorial). These instructions are defined in as\nconstants (and API documentation has description for their behavior). The instructions include:")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("MisfireInstruction.IgnoreMisfirePolicy")])]),t._v(" "),e("li",[e("code",[t._v("MisfireInstruction.CronTrigger.DoNothing")])]),t._v(" "),e("li",[e("code",[t._v("MisfireInstruction.CronTrigger.FireOnceNow")])])]),t._v(" "),e("p",[t._v("All triggers have the "),e("code",[t._v("MisfireInstrution.SmartPolicy")]),t._v(" instruction available for use, and this instruction is also the default for all trigger types.\nThe 'smart policy' instruction is interpreted by CronTrigger as MisfireInstruction.CronTrigger.FireOnceNow. The API documentation for the\n"),e("code",[t._v("CronTrigger.UpdateAfterMisfire()")]),t._v(" method explains the exact details of this behavior.")]),t._v(" "),e("p",[t._v("When building CronTriggers, you specify the misfire instruction as part of the cron schedule (via "),e("code",[t._v("WithCronSchedule")]),t._v(" extension method):")]),t._v(" "),e("div",{staticClass:"language-csharp extra-class"},[e("pre",{pre:!0,attrs:{class:"language-csharp"}},[e("code",[e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 0/2 8-17 * * ?"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" x "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithMisfireHandlingInstructionFireAndProceed")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/118.1a20ec6b.js b/assets/js/118.1a20ec6b.js new file mode 100644 index 000000000..23f889a93 --- /dev/null +++ b/assets/js/118.1a20ec6b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[118],{492:function(e,t,o){"use strict";o.r(t);var a=o(26),s=Object(a.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v('JobStore\'s are responsible for keeping track of all the "work data" that you give to the scheduler:\njobs, triggers, calendars, etc. Selecting the appropriate '),o("code",[e._v("IJobStore")]),e._v(" implementation for your Quartz scheduler instance is an important step.\nLuckily, the choice should be a very easy one once you understand the differences between them.\nYou declare which JobStore your scheduler should use (and it's configuration settings) in the properties file (or object) that\nyou provide to the SchedulerFactory that you use to produce your scheduler instance.")]),e._v(" "),o("div",{staticClass:"custom-block warning"},[o("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),o("p",[e._v("Never use a JobStore instance directly in your code. For some reason many people attempt to do this.\nThe JobStore is for behind-the-scenes use of Quartz itself. You have to tell Quartz (through configuration) which JobStore to use,\nbut then you should only work with the Scheduler interface in your code.")])]),e._v(" "),o("h2",{attrs:{id:"ramjobstore"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#ramjobstore"}},[e._v("#")]),e._v(" RAMJobStore")]),e._v(" "),o("p",[o("code",[e._v("RAMJobStore")]),e._v(" is the simplest JobStore to use, it is also the most performant (in terms of CPU time).\n"),o("code",[e._v("RAMJobStore")]),e._v(" gets its name in the obvious way: it keeps all of its data in RAM. This is why it's lightning-fast,\nand also why it's so simple to configure. The drawback is that when your application ends (or crashes) all of\nthe scheduling information is lost - this means RAMJobStore cannot honor the setting of \"non-volatility\" on jobs and triggers.\nFor some applications this is acceptable - or even the desired behavior, but for other applications, this may be disasterous.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring Quartz to use RAMJobStore")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("// this is actually the default, so you don't need to explicitly set this\nquartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz\n")])])]),o("p",[e._v("To use "),o("code",[e._v("RAMJobStore")]),e._v(" (and assuming you're using "),o("code",[e._v("StdSchedulerFactory")]),e._v(") you don't need to do anything special. Default configuration\nof Quartz.NET uses "),o("code",[e._v("RAMJobStore")]),e._v(" as job store implementation.")]),e._v(" "),o("h2",{attrs:{id:"ado-net-job-store-adojobstore"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#ado-net-job-store-adojobstore"}},[e._v("#")]),e._v(" ADO.NET Job Store (AdoJobStore)")]),e._v(" "),o("p",[e._v("AdoJobStore is also aptly named - it keeps all of its data in a database via ADO.NET.\nBecause of this it is a bit more complicated to configure than "),o("code",[e._v("RAMJobStore")]),e._v(", and it also is not as fast.\nHowever, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.")]),e._v(" "),o("p",[e._v('To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use.\nYou can find table-creation SQL scripts in the "database/dbtables" directory of the Quartz.NET distribution.\nIf there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB.\nOne thing to note is that in these scripts, all the the tables start with the prefix '),o("code",[e._v("QRTZ_")]),e._v("\n(such as the tables "),o("code",[e._v("QRTZ_TRIGGERS")]),e._v(", and "),o("code",[e._v("QRTZ_JOB_DETAIL")]),e._v("). This prefix can actually be anything you'd like, as long as you inform AdoJobStore\nwhat the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables,\nfor multiple scheduler instances, within the same database.")]),e._v(" "),o("p",[e._v("Currently the only option for the internal implementation of job store is "),o("code",[e._v("JobStoreTX")]),e._v("which creates transactions by itself.\nThis is different from Java version of Quartz where there is also option to choose "),o("code",[e._v("JobStoreCMT")]),e._v(" which uses J2EE container\nmanaged transactions.")]),e._v(" "),o("p",[e._v("The last piece of the puzzle is setting up a data source from which AdoJobStore can get connections to your database.\nData sources are defined in your Quartz.NET properties. Data source information contains the connection string\nand ADO.NET delegate information.")]),e._v(" "),o("h3",{attrs:{id:"configuring-quartz-to-use-jobstoretx"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#configuring-quartz-to-use-jobstoretx"}},[e._v("#")]),e._v(" Configuring Quartz to use JobStoreTx")]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz\n")])])]),o("p",[e._v("Next, you need to select a "),o("code",[e._v("IDriverDelegate")]),e._v(" implementation for the JobStore to use.\nThe DriverDelegate is responsible for doing any ADO.NET work that may be needed for your specific database.\n"),o("code",[e._v("StdAdoDelegate")]),e._v(' is a delegate that uses "vanilla" ADO.NET code (and SQL statements) to do its work.\nIf there isn\'t another delegate made specifically for your database, try using this delegate -\nspecial delegates usually have better performance or workarounds for database specific issues.\nOther delegates can be found in the '),o("code",[e._v("Quartz.Impl.AdoJobStore")]),e._v(" namespace, or in its sub-namespaces.")]),e._v(" "),o("div",{staticClass:"custom-block tip"},[o("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),o("p",[e._v("Quartz.NET will issue warning if you are using the default StdAdoDelegate as it has poor performance\nwhen you have a lot of triggers to select from. Specific delegates have special SQL to limit result\nset length (SqlServerDelegate uses "),o("code",[e._v("TOP n")]),e._v(", PostgreSQLDelegate "),o("code",[e._v("LIMIT n")]),e._v(", OracleDelegate "),o("code",[e._v("ROWCOUNT() <= n")]),e._v(" etc.).")])]),e._v(" "),o("p",[e._v("Once you've selected your delegate, set its class name as the delegate for AdoJobStore to use.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore to use a DriverDelegate")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz\n")])])]),o("p",[e._v("Next, you need to inform the JobStore what table prefix (discussed above) you are using.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore with the Table Prefix")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.tablePrefix = QRTZ_\n")])])]),o("p",[e._v('And finally, you need to set which data source should be used by the JobStore. The named data source must also be defined in your Quartz properties.\nIn this case, we\'re specifying that Quartz should use the data source name "myDS" (that is defined elsewhere in the configuration properties).')]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore with the name of the data source to use")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.dataSource = myDS\n")])])]),o("p",[e._v("One last thing that is needed for the configuration is to set data source connection string information and database provider. Connection\nstring is the standard ADO.NET connection which is driver specific. Database provider is an abstraction of database drivers to create\nloose coupling between database drivers and Quartz.")]),e._v(" "),o("p",[o("strong",[e._v("Setting Data Source's Connection String And Database Provider")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v(" quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartz;Uid=quartznet;Pwd=quartznet\n quartz.dataSource.myDS.provider = MySql\n")])])]),o("p",[e._v("Currently following database providers are supported:")]),e._v(" "),o("ul",[o("li",[o("code",[e._v("SqlServer")]),e._v(" - SQL Server driver\n"),o("ul",[o("li",[e._v("For full framework this is by default System.Data.SqlClient (except in Quartz 3.1)")]),e._v(" "),o("li",[e._v("From Quartz 3.2 onwards for .NET Core this is by default Microsoft.Data.SqlClient")])])]),e._v(" "),o("li",[o("code",[e._v("SystemDataSqlClient")]),e._v(" - Available separately on .NET Core (default for full framework)")]),e._v(" "),o("li",[o("code",[e._v("MicrosoftDataSqlClient")]),e._v(" - Available separately on full framework (default for .NET Core)")]),e._v(" "),o("li",[o("code",[e._v("OracleODP")]),e._v(" - Oracle's Oracle Driver")]),e._v(" "),o("li",[o("code",[e._v("OracleODPManaged")]),e._v(" - Oracle's managed driver for Oracle 11")]),e._v(" "),o("li",[o("code",[e._v("MySql")]),e._v(" - MySQL Connector/.NET")]),e._v(" "),o("li",[o("code",[e._v("SQLite")]),e._v(" - SQLite ADO.NET Provider")]),e._v(" "),o("li",[o("code",[e._v("SQLite-Microsoft")]),e._v(" - Microsoft SQLite ADO.NET Provider")]),e._v(" "),o("li",[o("code",[e._v("Firebird")]),e._v(" - Firebird ADO.NET Provider")]),e._v(" "),o("li",[o("code",[e._v("Npgsql")]),e._v(" - PostgreSQL Npgsql")])]),e._v(" "),o("div",{staticClass:"custom-block tip"},[o("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),o("p",[e._v("There are many community contributed providers, like for NoSQL databases.")]),e._v(" "),o("p",[e._v("They are not supported by Quartz.NET project though.")])]),e._v(" "),o("p",[o("strong",[e._v("You can and should use latest version of driver if newer is available, just create an assembly binding redirect")])]),e._v(" "),o("p",[e._v("If your Scheduler is very busy (i.e. nearly always executing the same number of jobs as the size of the thread pool, then you should\nprobably set the number of connections in the data source to be the about the size of the thread pool + 1.This is commonly configured\nint the ADO.NET connection string - see your driver implementation for details.")]),e._v(" "),o("p",[e._v("The "),o("code",[e._v("quartz.jobStore.useProperties")]),e._v(' config parameter can be set to "true" (defaults to false) in order to instruct AdoJobStore that all values in JobDataMaps will be strings,\nand therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column. This is much safer in the long term,\nas you avoid the class versioning issues that there are with serializing your non-String classes into a BLOB.')]),e._v(" "),o("h3",{attrs:{id:"configuring-adojobstore-to-use-strings-as-jobdatamap-values"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#configuring-adojobstore-to-use-strings-as-jobdatamap-values"}},[e._v("#")]),e._v(" Configuring AdoJobStore to use strings as JobDataMap values")]),e._v(" "),o("div",{staticClass:"custom-block tip"},[o("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),o("p",[e._v("This is recommended configuration because it greatly decreases the possibility of type serialization issues.")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.useProperties = true\n")])])]),o("h3",{attrs:{id:"choosing-a-serializer"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#choosing-a-serializer"}},[e._v("#")]),e._v(" Choosing a serializer")]),e._v(" "),o("p",[e._v("Quartz.NET supports both binary and JSON serialization.\nJSON serialization comes from separate "),o("a",{attrs:{href:"../packages/json-serialization"}},[e._v("Quartz.Serialization.Json")]),e._v(" NuGet package.")]),e._v(" "),o("div",{staticClass:"custom-block tip"},[o("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),o("p",[e._v("JSON is recommended persistent format to store data in database for greenfield projects.\nYou should also strongly consider setting useProperties to true to restrict key-values to be strings.")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v('// "json" is alias for "Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json" \nquartz.serializer.type = json\n')])])])])}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/119.5545109a.js b/assets/js/119.5545109a.js new file mode 100644 index 000000000..a6775f6ad --- /dev/null +++ b/assets/js/119.5545109a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[119],{493:function(e,t,a){"use strict";a.r(t);var s=a(26),n=Object(s.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h2",{attrs:{id:"the-quartz-api"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#the-quartz-api"}},[e._v("#")]),e._v(" The Quartz API")]),e._v(" "),a("p",[e._v("The key interfaces and classes of the Quartz API are:")]),e._v(" "),a("ul",[a("li",[a("code",[e._v("IScheduler")]),e._v(" - the main API for interacting with the scheduler.")]),e._v(" "),a("li",[a("code",[e._v("IJob")]),e._v(" - an interface to be implemented by components that you wish to have executed by the scheduler.")]),e._v(" "),a("li",[a("code",[e._v("IJobDetail")]),e._v(" - used to define instances of Jobs.")]),e._v(" "),a("li",[a("code",[e._v("ITrigger")]),e._v(" - a component that defines the schedule upon which a given Job will be executed, job can have multiple associated triggers")]),e._v(" "),a("li",[a("code",[e._v("JobBuilder")]),e._v(" - used to define/build JobDetail instances, which define instances of Jobs.")]),e._v(" "),a("li",[a("code",[e._v("TriggerBuilder")]),e._v(" - used to define/build Trigger instances.")]),e._v(" "),a("li",[a("code",[e._v("SchedulerBuilder")]),e._v(" - used to define/build scheduler instances, requires Quartz 3.1 or later.")])]),e._v(" "),a("p",[e._v("In this tutorial for readability's sake following terms are used interchangeably: "),a("code",[e._v("IScheduler")]),e._v(" and "),a("code",[e._v("Scheduler")]),e._v(", "),a("code",[e._v("IJob")]),e._v(" and "),a("code",[e._v("Job")]),e._v(", "),a("code",[e._v("IJobDetail")]),e._v(" and "),a("code",[e._v("JobDetail")]),e._v(", "),a("code",[e._v("ITrigger")]),e._v(" and "),a("code",[e._v("Trigger")]),e._v(".")]),e._v(" "),a("p",[e._v("A "),a("code",[e._v("Scheduler")]),e._v("'s life-cycle is bounded by it's creation, via a "),a("code",[e._v("SchedulerFactory")]),e._v(" and a call to its "),a("code",[e._v("Shutdown()")]),e._v(" method.\nOnce created the "),a("code",[e._v("IScheduler")]),e._v(" interface can be used add, remove, and list Jobs and Triggers, and perform other scheduling-related operations (such as pausing a trigger).\nHowever, the Scheduler will not actually act on any triggers (execute jobs) until it has been started with the "),a("code",[e._v("Start()")]),e._v(" method, as shown in "),a("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/using-quartz.html"}},[e._v("Lesson 1")]),e._v(".")],1),e._v(" "),a("p",[e._v('Quartz provides "builder" classes that define a Domain Specific Language (or DSL, also sometimes referred to as a "fluent interface"). In the previous lesson you saw an example of it, which we present a portion of here again:')]),e._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// define the job and tie it to our HelloJob class")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("IJobDetail")]),e._v(" job "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" JobBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Create")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("<")]),e._v("HelloJob"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"myJob"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v('// name "myJob", group "group1"')]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n \n"),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// Trigger the job to run now, and then every 40 seconds")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("ITrigger")]),e._v(" trigger "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" TriggerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"myTrigger"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("StartNow")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("WithSimpleSchedule")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=>")]),e._v(" x\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("WithIntervalInSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("40")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("RepeatForever")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n \n"),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// Tell quartz to schedule the job using our trigger")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("await")]),e._v(" sched"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("scheduleJob")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("job"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n")])])]),a("p",[e._v("The block of code that builds the job definition is using "),a("code",[e._v("JobBuilder")]),e._v(" using fluent interface to create the product, "),a("code",[e._v("IJobDetail")]),e._v(".\nLikewise, the block of code that builds the trigger is using "),a("code",[e._v("TriggerBuilder")]),e._v("'s fluent interface and extension methods that are specific to given trigger type.\nPossible schedule extension methods are:")]),e._v(" "),a("ul",[a("li",[a("code",[e._v("WithCalendarIntervalSchedule")])]),e._v(" "),a("li",[a("code",[e._v("WithCronSchedule")])]),e._v(" "),a("li",[a("code",[e._v("WithDailyTimeIntervalSchedule")])]),e._v(" "),a("li",[a("code",[e._v("WithSimpleSchedule")])])]),e._v(" "),a("p",[e._v("The "),a("code",[e._v("DateBuilder")]),e._v(" type contains various methods for easily constructing DateTimeOffset instances for particular points in time\n(such as a date that represents the next even hour - or in other words 10:00:00 if it is currently 9:43:27).")]),e._v(" "),a("h2",{attrs:{id:"jobs-and-triggers"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobs-and-triggers"}},[e._v("#")]),e._v(" Jobs and Triggers")]),e._v(" "),a("p",[e._v("A job is a class that implements the "),a("code",[e._v("IJob")]),e._v(" interface, which has only one simple method:")]),e._v(" "),a("p",[a("strong",[e._v("IJob Interface")])]),e._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("namespace")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[e._v("Quartz")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("interface")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("IJob")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[e._v("Task")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Execute")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("JobExecutionContext")]),e._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),a("p",[e._v("When the Job's trigger fires (more on that in a moment), the "),a("code",[e._v("Execute(..)")]),e._v(" method is invoked by one of the scheduler's worker threads.\nThe "),a("code",[e._v("JobExecutionContext")]),e._v(' object that is passed to this method provides the job instance with information about its "run-time" environment -\na handle to the Scheduler that executed it, a handle to the Trigger that triggered the execution, the job\'s JobDetail object, and a few other items.')]),e._v(" "),a("p",[e._v("The JobDetail object is created by the Quartz.NET client (your program) at the time the Job is added to the scheduler.\nIt contains various property settings for the Job, as well as a JobDataMap, which can be used to store state information for a given instance of your job class.\nIt is essentially the definition of the job instance, and is discussed in further detail in the next lesson.")]),e._v(" "),a("p",[e._v("Trigger objects are used to trigger the execution (or 'firing') of jobs. When you wish to schedule a job, you instantiate a trigger and 'tune' its properties\nto provide the scheduling you wish to have. Triggers may also have a JobDataMap associated with them - this is useful to passing parameters to a\nJob that are specific to the firings of the trigger. Quartz ships with a handful of different trigger types, but the most commonly used types\nare SimpleTrigger (interface "),a("code",[e._v("ISimpleTrigger")]),e._v(") and CronTrigger (interface "),a("code",[e._v("ICronTrigger")]),e._v(").")]),e._v(" "),a("p",[e._v('SimpleTrigger is handy if you need \'one-shot\' execution (just single execution of a job at a given moment in time), or if you need to fire a job at a given time,\nand have it repeat N times, with a delay of T between executions. CronTrigger is useful if you wish to have triggering based on calendar-like schedules -\nsuch as "every Friday, at noon" or "at 10:15 on the 10th day of every month."')]),e._v(" "),a("p",[e._v("Why Jobs AND Triggers? Many job schedulers do not have separate notions of jobs and triggers. Some define a 'job' as simply an execution time (or schedule)\nalong with some small job identifier. Others are much like the union of Quartz's job and trigger objects. While developing Quartz, we decided that it made sense\nto create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits.")]),e._v(" "),a("p",[e._v("For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job.\nAnother benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired,\nso that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define\nits associated job.")]),e._v(" "),a("h2",{attrs:{id:"identities"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#identities"}},[e._v("#")]),e._v(" Identities")]),e._v(" "),a("p",[e._v("Jobs and Triggers are given identifying keys as they are registered with the Quartz scheduler.\nThe keys of Jobs and Triggers ("),a("code",[e._v("JobKey")]),e._v(" and "),a("code",[e._v("TriggerKey")]),e._v(') allow them to be placed into \'groups\' which can be useful for organizing your jobs and\ntriggers into categories such as "reporting jobs" and "maintenance jobs". The name portion of the key of a job or trigger must be unique within the group')]),e._v(" "),a("ul",[a("li",[e._v("or in other words, the complete key (or identifier) of a job or trigger is the compound of the name and group.")])]),e._v(" "),a("p",[e._v("You now have a general idea about what Jobs and Triggers are, you can learn more about them in\n"),a("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/more-about-jobs.html"}},[e._v("Lesson 3: More About Jobs & JobDetails")]),e._v(" and "),a("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/more-about-triggers.html"}},[e._v("Lesson 4: More About Triggers")])],1)])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/12.632699a6.js b/assets/js/12.632699a6.js new file mode 100644 index 000000000..99b9ce742 --- /dev/null +++ b/assets/js/12.632699a6.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{385:function(e,t,n){"use strict";n.r(t);n(50),n(70);var o={name:"Redirect",props:{to:{type:String,required:!0}},beforeMount:function(){document.location.replace(this.to)}},r=n(26),i=Object(r.a)(o,(function(){var e=this.$createElement;return(this._self._c||e)("div")}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/120.ac3b1282.js b/assets/js/120.ac3b1282.js new file mode 100644 index 000000000..a9cf6873c --- /dev/null +++ b/assets/js/120.ac3b1282.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[120],{494:function(t,e,a){"use strict";a.r(e);var o=a(26),n=Object(o.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"plug-ins"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#plug-ins"}},[t._v("#")]),t._v(" Plug-Ins")]),t._v(" "),a("p",[t._v("Quartz provides an interface ("),a("code",[t._v("ISchedulerPlugin")]),t._v(") for plugging-in additional functionality.")]),t._v(" "),a("p",[t._v("Plugins that ship with Quartz to provide various utility capabilities can be found documented in the "),a("code",[t._v("Quartz.Plugins")]),t._v(" namespace.\nThey provide functionality such as auto-scheduling of jobs upon scheduler startup, logging a history of job and trigger events,\nand ensuring that the scheduler shuts down cleanly when the virtual machine exits.")]),t._v(" "),a("h2",{attrs:{id:"jobfactory"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobfactory"}},[t._v("#")]),t._v(" JobFactory")]),t._v(" "),a("p",[t._v("When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler.\nThe default JobFactory simply activates a new instance of the job class. You may want to create your own implementation\nof JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.")]),t._v(" "),a("p",[t._v("See the "),a("code",[t._v("IJobFactory")]),t._v(" interface, and the associated "),a("code",[t._v("IScheduler.JobFactory")]),t._v(" setter property.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("Since Quartz 3.1, there's "),a("a",{attrs:{href:"../packages/microsoft-di-integration"}},[t._v("built-in support for integrating with Microsoft Dependency Injection")]),t._v(" which in\nturn allows to use different IoC container implementations.")])]),t._v(" "),a("h2",{attrs:{id:"factory-shipped-jobs"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factory-shipped-jobs"}},[t._v("#")]),t._v(" 'Factory-Shipped' Jobs")]),t._v(" "),a("p",[t._v("Quartz also provides a number of utility Jobs that you can use in your application for doing things like sending\ne-mails and invoking remote objects. These out-of-the-box Jobs can be found documented in the "),a("code",[t._v("Quartz.Jobs")]),t._v(" namespace and\nare part of the "),a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Jobs",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Jobs NuGet package"),a("OutboundLink")],1),t._v(".")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/121.b9c8a72f.js b/assets/js/121.b9c8a72f.js new file mode 100644 index 000000000..410a95a63 --- /dev/null +++ b/assets/js/121.b9c8a72f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[121],{495:function(t,a,s){"use strict";s.r(a);var e=s(26),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("As you saw in Lesson 2, jobs are rather easy to implement. There are just a few more things that you need to understand about\nthe nature of jobs, about the "),s("code",[t._v("Execute(..)")]),t._v(" method of the "),s("code",[t._v("IJob")]),t._v(" interface, and about JobDetails.")]),t._v(" "),s("p",[t._v("While a job class that you implement has the code that knows how to do the actual work\nof the particular type of job, Quartz.NET needs to be informed about various attributes\nthat you may wish an instance of that job to have. This is done via the JobDetail class,\nwhich was mentioned briefly in the previous section.")]),t._v(" "),s("p",[t._v("JobDetail instances are built using the "),s("code",[t._v("JobBuilder")]),t._v(" class. "),s("code",[t._v("JobBuilder")]),t._v(" allows you to describe\nyour job's details using a fluent interface.")]),t._v(" "),s("p",[t._v("Let's take a moment now to discuss a bit about the 'nature' of jobs and the life-cycle of job instances within Quartz.NET.\nFirst lets take a look back at some of that snippet of code we saw in Lesson 1:")]),t._v(" "),s("p",[s("strong",[t._v("Using Quartz.NET")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then every 40 seconds")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n\t "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("40")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \nsched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("Now consider the job class "),s("strong",[t._v("HelloJob")]),t._v(" defined as such:")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HelloJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLineAsync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"HelloJob is executing."')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Notice that we give the scheduler a "),s("code",[t._v("IJobDetail")]),t._v(" instance, and that it refers to the job to be executed by simply\nproviding the job's class. Each (and every) time the scheduler executes the job, it creates a new instance of the\nclass before calling its "),s("code",[t._v("Execute(..)")]),t._v(" method. One of the ramifications of this behavior is the fact that jobs must\nhave a no-arguement constructor. Another ramification is that it does not make sense to have data-fields defined\non the job class - as their values would not be preserved between job executions.")]),t._v(" "),s("p",[t._v('You may now be wanting to ask "how can I provide properties/configuration for a Job instance?" and "how can I\nkeep track of a job\'s state between executions?" The answer to these questions are the same: the key is the '),s("code",[t._v("JobDataMap")]),t._v(",\nwhich is part of the JobDetail object.")]),t._v(" "),s("h2",{attrs:{id:"jobdatamap"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#jobdatamap"}},[t._v("#")]),t._v(" JobDataMap")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("JobDataMap")]),t._v(" can be used to hold any number of (serializable) objects which you wish to have made available\nto the job instance when it executes. "),s("code",[t._v("JobDataMap")]),t._v(" is an implementation of the "),s("code",[t._v("IDictionary")]),t._v(" interface, and has\nsome added convenience methods for storing and retrieving data of primitive types.")]),t._v(" "),s("p",[t._v("Here's some quick snippets of putting data into the JobDataMap prior to adding the job to the scheduler:")]),t._v(" "),s("p",[s("strong",[t._v("Setting Values in a JobDataMap")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our DumbJob class")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("DumbJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// name "myJob", group "group1"')]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Hello World!"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3.141f")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("Here's a quick example of getting data from the JobDataMap during the job's execution:")]),t._v(" "),s("p",[s("strong",[t._v("Getting Values from a JobDataMap")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobKey")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" myFloatValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetFloat")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLineAsync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" of DumbJob says: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", and val is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" myFloatValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("If you use a persistent JobStore (discussed in the JobStore section of this tutorial) you should use some care\nin deciding what you place in the JobDataMap, because the object in it will be serialized, and they therefore\nbecome prone to class-versioning problems. Obviously standard .NET types should be very safe, but beyond that,\nany time someone changes the definition of a class for which you have serialized instances,\ncare has to be taken not to break compatibility.")]),t._v(" "),s("p",[t._v("Optionally, you can put AdoJobStore and JobDataMap into a mode where only primitives\nand strings can be stored in the map, thus eliminating any possibility of later serialization problems.")]),t._v(" "),s("p",[t._v("If you add properties with set accessor to your job class that correspond to the names of keys in the JobDataMap,\nthen Quartz's default JobFactory implementation will automatically call those setters when the job is instantiated,\nthus preventing the need to explicitly get the values out of the map within your execute method. Note this\nfunctionality is not maintained by default when using a custom JobFactory.")]),t._v(" "),s("p",[t._v("Triggers can also have JobDataMaps associated with them. This can be useful in the case where you have a Job that is stored in the scheduler\nfor regular/repeated use by multiple Triggers, yet with each independent triggering, you want to supply the Job with different data inputs.")]),t._v(" "),s("p",[t._v("The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge of the JobDataMap\nfound on the JobDetail and the one found on the Trigger, with the values in the latter overriding any same-named values in the former.")]),t._v(" "),s("p",[t._v("Here's a quick example of getting data from the JobExecutionContext's merged JobDataMap during the job's execution:")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobKey")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MergedJobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note the difference from the previous example")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" myFloatValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetFloat")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" state "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("IList"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myStateData"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\tstate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLineAsync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" of DumbJob says: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", and val is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" myFloatValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v('Or if you wish to rely on the JobFactory "injecting" the data map values onto your class, it might look like this instead:')]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" JobSays "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" MyFloatValue "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobKey")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MergedJobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note the difference from the previous example")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" state "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("IList"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myStateData"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\tstate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLineAsync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" of DumbJob says: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" JobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", and val is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" MyFloatValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("You'll notice that the overall code of the class is longer, but the code in the "),s("code",[t._v("Execute()")]),t._v(" method is cleaner.\nOne could also argue that although the code is longer, that it actually took less coding, if the programmer's IDE was used to auto-generate the properties,\nrather than having to hand-code the individual calls to retrieve the values from the JobDataMap. The choice is yours.")]),t._v(" "),s("h2",{attrs:{id:"job-instances"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#job-instances"}},[t._v("#")]),t._v(' Job "Instances"')]),t._v(" "),s("p",[t._v('Many users spend time being confused about what exactly constitutes a "job instance".\nWe\'ll try to clear that up here and in the section below about job state and concurrency.')]),t._v(" "),s("p",[t._v("You can create a single job class, and store many 'instance definitions' of it within the scheduler by creating multiple instances of JobDetails")]),t._v(" "),s("ul",[s("li",[t._v("each with its own set of properties and JobDataMap - and adding them all to the scheduler.")])]),t._v(" "),s("p",[t._v("For example, you can create a class that implements the "),s("code",[t._v("IJob")]),t._v(' interface called "SalesReportJob".\nThe job might be coded to expect parameters sent to it (via the JobDataMap) to specify the name of the sales person that the sales\nreport should be based on. They may then create multiple definitions (JobDetails) of the job, such as "SalesReportForJoe"\nand "SalesReportForMike" which have "joe" and "mike" specified in the corresponding JobDataMaps as input to the respective jobs.')]),t._v(" "),s("p",[t._v("When a trigger fires, the JobDetail (instance definition) it is associated to is loaded,\nand the job class it refers to is instantiated via the JobFactory configured on the Scheduler.\nThe default JobFactory simply calls the default constructor of the job class using Activator.CreateInstance,\nthen attempts to call setter properties on the class that match the names of keys within the JobDataMap.\nYou may want to create your own implementation of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.")]),t._v(" "),s("p",[t._v('In "Quartz speak", we refer to each stored JobDetail as a "job definition" or "JobDetail instance",\nand we refer to a each executing job as a "job instance" or "instance of a job definition".\nUsually if we just use the word "job" we are referring to a named definition, or JobDetail.\nWhen we are referring to the class implementing the job interface, we usually use the term "job type".')]),t._v(" "),s("h2",{attrs:{id:"job-state-and-concurrency"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#job-state-and-concurrency"}},[t._v("#")]),t._v(" Job State and Concurrency")]),t._v(" "),s("p",[t._v("Now, some additional notes about a job's state data (aka JobDataMap) and concurrency.\nThere are a couple attributes that can be added to your Job class that affect Quartz's behaviour with respect to these aspects.")]),t._v(" "),s("p",[s("code",[t._v("[DisallowConcurrentExecution]")]),t._v(' is an attribute that can be added to the Job class that tells Quartz not to execute multiple instances\nof a given job definition (that refers to the given job class) concurrently.\nNotice the wording there, as it was chosen very carefully. In the example from the previous section, if "SalesReportJob" has this attribute,\nthen only one instance of "SalesReportForJoe" can execute at a given time, but it can execute concurrently with an instance of "SalesReportForMike".\nThe constraint is based upon an instance definition (JobDetail), not on instances of the job class.\nHowever, it was decided (during the design of Quartz) to have the attribute carried on the class itself, because it does often make a difference to how the class is coded.')]),t._v(" "),s("p",[s("code",[t._v("[PersistJobDataAfterExecution]")]),t._v(" is an attribute that can be added to the Job class that tells Quartz to update the stored copy of\nthe JobDetail's JobDataMap after the Execute() method completes successfully (without throwing an exception), such that the next\nexecution of the same job (JobDetail) receives the updated values rather than the originally stored values.\nLike the "),s("code",[t._v("[DisallowConcurrentExecution]")]),t._v(" attribute, this applies to a job definition instance, not a job class instance,\nthough it was decided to have the job class carry the attribute because it does often make a difference to how the class is coded\n(e.g. the 'statefulness' will need to be explicitly 'understood' by the code within the execute method).")]),t._v(" "),s("p",[t._v("If you use the "),s("strong",[t._v("PersistJobDataAfterExecution")]),t._v(" attribute, you should strongly consider also using the "),s("code",[t._v("[DisallowConcurrentExecution]")]),t._v(" attribute,\nin order to avoid possible confusion (race conditions) of what data was left stored when two instances of the same job (JobDetail) executed concurrently.")]),t._v(" "),s("h2",{attrs:{id:"other-attributes-of-jobs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#other-attributes-of-jobs"}},[t._v("#")]),t._v(" Other Attributes Of Jobs")]),t._v(" "),s("p",[t._v("Here's a quick summary of the other properties which can be defined for a job instance via the JobDetail object:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("Durability")]),t._v(" - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it.\nIn other words, non-durable jobs have a life span bounded by the existence of its triggers.")]),t._v(" "),s("li",[s("code",[t._v("RequestsRecovery")]),t._v(" - if a job \"requests recovery\", and it is executing during the time of a 'hard shutdown' of the scheduler\n(i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again.\nIn this case, the "),s("code",[t._v("JobExecutionContext.Recovering")]),t._v(" property will return true.")])]),t._v(" "),s("h2",{attrs:{id:"jobexecutionexception"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#jobexecutionexception"}},[t._v("#")]),t._v(" JobExecutionException")]),t._v(" "),s("p",[t._v("Finally, we need to inform you of a few details of the "),s("code",[t._v("IJob.Execute(..)")]),t._v(" method. The only type of exception\nthat you should throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire contents of the\nexecute method with a 'try-catch' block. You should also spend some time looking at the documentation for the JobExecutionException,\nas your job can use it to provide the scheduler various directives as to how you want the exception to be handled.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/122.702d9fad.js b/assets/js/122.702d9fad.js new file mode 100644 index 000000000..b10ef0a11 --- /dev/null +++ b/assets/js/122.702d9fad.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[122],{496:function(t,e,s){"use strict";s.r(e);var a=s(26),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("Like jobs, triggers are relatively easy to work with, but do contain a variety of customizable options that you need to\nbe aware of and understand before you can make full use of Quartz.NET. Also, as noted earlier, there are different types of triggers,\nthat you can select to meet different scheduling needs.")]),t._v(" "),s("h2",{attrs:{id:"common-trigger-attributes"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#common-trigger-attributes"}},[t._v("#")]),t._v(" Common Trigger Attributes")]),t._v(" "),s("p",[t._v("Aside from the fact that all trigger types have "),s("code",[t._v("TriggerKey")]),t._v(" properties for tracking their identities,\nthere are a number of other properties that are common to all trigger types. These common properties are set using the TriggerBuilder\nwhen you are building the trigger definition (examples of that will follow).")]),t._v(" "),s("p",[t._v("Here is a listing of properties common to all trigger types:")]),t._v(" "),s("ul",[s("li",[t._v("The "),s("code",[t._v("JobKey")]),t._v(" property indicates the identity of the job that should be executed when the trigger fires.")]),t._v(" "),s("li",[t._v("The "),s("code",[t._v("StartTimeUtc")]),t._v(' property indicates when the trigger\'s schedule first comes into affect.\nThe value is a DateTimeOffset object that defines a moment in time on a given calendar date.\nFor some trigger types, the trigger will actually fire at the start time, for others it simply marks the time that the schedule should start being followed.\nThis means you can store a trigger with a schedule such as "every 5th day of the month" during January, and if the StartTimeUtc property is set to April 1st,\nit will be a few months before the first firing.')]),t._v(" "),s("li",[t._v("The "),s("code",[t._v("EndTimeUtc")]),t._v(" property indicates when the trigger's schedule should no longer be in effect.\nIn other words, a trigger with a schedule of \"every 5th day of the month\" and with an end time of July 1st will fire for it's last time on June 5th.")])]),t._v(" "),s("p",[t._v("Other properties, which take a bit more explanation are discussed in the following sub-sections.")]),t._v(" "),s("h2",{attrs:{id:"priority"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#priority"}},[t._v("#")]),t._v(" Priority")]),t._v(" "),s("p",[t._v("Sometimes, when you have many Triggers (or few worker threads in your Quartz.NET thread pool), Quartz.NET may not have enough resources to immediately fire all\nof the Triggers that are scheduled to fire at the same time. In this case, you may want to control which of your Triggers get first crack at the available Quartz.NET worker threads.\nFor this purpose, you can set the priority property on a Trigger. If N Triggers are to fire at the same time, but there are only Z worker threads currently available,\nthen the first Z Triggers with the highest priority will be executed first. If you do not set a priority on a Trigger, then it will use the default priority of 5.\nAny integer value is allowed for priority, positive or negative. A larger number indicates a higher priority. i.e. A trigger with a Priority of 7 will have priority over trigger with a value of 5.")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("Priorities are only compared when triggers have the same fire time. A trigger scheduled to fire at 10:59 will always fire before one scheduled to fire at 11:00.")])]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("When a trigger's job is detected to require recovery, its recovery is scheduled with the same priority as the original trigger.")])]),t._v(" "),s("h2",{attrs:{id:"misfire-instructions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#misfire-instructions"}},[t._v("#")]),t._v(" Misfire Instructions")]),t._v(" "),s("p",[t._v('Another important property of a Trigger is its "misfire instruction". A misfire occurs if a persistent trigger "misses" its firing time because of the scheduler being shutdown,\nor because there are no available threads in Quartz.NET\'s thread pool for executing the job.\nThe different trigger types have different misfire instructions available to them.\nBy default they use a \'smart policy\' instruction - which has dynamic behavior based on trigger type and configuration.\nWhen the scheduler starts, it searches for any persistent triggers that have misfired, and it then updates each of them based on their individually\nconfigured misfire instructions. When you start using Quartz.NET in your own projects, you should make yourself familiar with the misfire instructions\nthat are defined on the given trigger types, and explained in their API documentation. More specific information about misfire instructions will be given within\nthe tutorial lessons specific to each trigger type.')]),t._v(" "),s("h2",{attrs:{id:"calendars"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#calendars"}},[t._v("#")]),t._v(" Calendars")]),t._v(" "),s("p",[t._v("Quartz.NET Calendar objects implementing "),s("code",[t._v("ICalendar")]),t._v(" interface can be associated with triggers at the time the trigger is stored in the scheduler.\nCalendars are useful for excluding blocks of time from the trigger's firing schedule. For instance, you could\ncreate a trigger that fires a job every weekday at 9:30 am, but then add a Calendar that excludes all of the business's holidays.")]),t._v(" "),s("p",[t._v("Calendar's can be any serializable objects that implement the ICalendar interface, which looks like this:")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("namespace")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ICalendar")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Description "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("ICalendar")]),t._v(" CalendarBase "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("IsTimeIncluded")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DateTimeOffset")]),t._v(" timeUtc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("DateTime")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetNextIncludedTimeUtc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DateTimeOffset")]),t._v(" timeUtc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("ICalendar")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),s("p",[t._v("Even though calendars can 'block out' sections of time as narrow as a millisecond, most likely, you'll be interested in\n'blocking-out' entire days. As a convenience, Quartz.NET includes the class HolidayCalendar, which does just that.")]),t._v(" "),s("p",[t._v("Calendars must be instantiated and registered with the scheduler via the "),s("code",[t._v("AddCalendar(..)")]),t._v(" method. If you use "),s("code",[t._v("HolidayCalendar")]),t._v(",\nafter instantiating it, you should use its "),s("code",[t._v("AddExcludedDate(DateTime date)")]),t._v(" method in order to populate it with the days you wish\nto have excluded from scheduling. The same calendar instance can be used with multiple triggers such as this:")]),t._v(" "),s("p",[s("strong",[t._v("Calendar Example")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HolidayCalendar")]),t._v(" cal "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("HolidayCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n cal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddExcludedDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("someDate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" t "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DailyAtHourAndMinute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// execute job daily at 9:30")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ModifiedByCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// but not on holidays")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. schedule job with trigger")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" t2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DailyAtHourAndMinute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// execute job daily at 11:30")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ModifiedByCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// but not on holidays")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. schedule job with trigger2 ")]),t._v("\n")])])]),s("p",[t._v("The details of the construction/building of triggers will be given in the next couple lessons.\nFor now, just believe that the code above creates two triggers, each scheduled to fire daily.\nHowever, any of the firings that would have occurred during the period excluded by the calendar will be skipped.")]),t._v(" "),s("p",[t._v("See the Quartz.Impl.Calendar namespace for a number of ICalendar implementations that may suit your needs.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/123.b873e59c.js b/assets/js/123.b873e59c.js new file mode 100644 index 000000000..91c2836f3 --- /dev/null +++ b/assets/js/123.b873e59c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[123],{520:function(s,t,a){"use strict";a.r(t);var e=a(26),n=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("p",[s._v("SchedulerListeners are much like "),a("code",[s._v("ITriggerListener")]),s._v("s and "),a("code",[s._v("IJobListener")]),s._v("s, except they receive notification of\nevents within the scheduler itself - not necessarily events related to a specific trigger or job.")]),s._v(" "),a("p",[s._v("Scheduler-related events include: the addition of a job/trigger, the removal of a job/trigger, a serious error\nwithin the scheduler, notification of the scheduler being shutdown, and others.")]),s._v(" "),a("div",{staticClass:"custom-block danger"},[a("p",{staticClass:"custom-block-title"},[s._v("WARNING")]),s._v(" "),a("p",[s._v("Make sure your scheduler listeners never throw an exception (use a try-catch) and that they can handle internal problems.\nQuartz can get in unpredictable state when it is unable to determine whether required logic in listener was completed successfully when listener notification failed.")])]),s._v(" "),a("p",[a("strong",[s._v("The ISchedulerListener Interface")])]),s._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("interface")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("ISchedulerListener")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobScheduled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Trigger")]),s._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobUnscheduled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggerFinalized")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Trigger")]),s._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggersPaused")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggersResumed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobsPaused")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobsResumed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("SchedulerError")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" msg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("SchedulerException")]),s._v(" cause"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s._v("Task")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("SchedulerShutdown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" \n")])])]),a("p",[s._v("SchedulerListeners are registered with the scheduler's "),a("code",[s._v("ListenerManager")]),s._v(".\nSchedulerListeners can be virtually any object that implements the "),a("code",[s._v("ISchedulerListener")]),s._v(" interface.")]),s._v(" "),a("p",[a("strong",[s._v("Adding a SchedulerListener:")])]),s._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[s._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("AddSchedulerListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("mySchedListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])])]),a("p",[a("strong",[s._v("Removing a SchedulerListener:")])]),s._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[s._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("RemoveSchedulerListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("mySchedListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/124.73484c48.js b/assets/js/124.73484c48.js new file mode 100644 index 000000000..61440739e --- /dev/null +++ b/assets/js/124.73484c48.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[124],{519:function(t,s,n){"use strict";n.r(s);var a=n(26),e=Object(a.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[t._v("SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time,\nor at a specific moment in time followed by repeats at a specific interval. Or plainer english, if you want the trigger to\nfire at exactly 11:23:54 AM on January 13, 2005, and then fire five more times, every ten seconds.")]),t._v(" "),n("p",[t._v("With this description, you may not find it surprising to find that the properties of a SimpleTrigger include: a start-time,\nand end-time, a repeat count, and a repeat interval. All of these properties are exactly what you'd expect them to be, with\nonly a couple special notes related to the end-time property.")]),t._v(" "),n("p",[t._v("The repeat count can be zero, a positive integer, or the constant value "),n("code",[t._v("SimpleTrigger.RepeatIndefinitely")]),t._v(".\nThe repeat interval property must be "),n("code",[t._v("TimeSpan.Zero")]),t._v(", or a positive TimeSpan value.\nNote that a repeat interval of zero will cause 'repeat count' firings of the trigger to happen concurrently\n(or as close to concurrently as the scheduler can manage).")]),t._v(" "),n("p",[t._v("If you're not already familiar with the "),n("code",[t._v("DateTime")]),t._v(" class, you may find it helpful for computing your trigger fire-times,\ndepending on the startTimeUtc (or endTimeUtc) that you're trying to create.")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("EndTimeUtc")]),t._v(" property (if it is specified) over-rides the repeat count property. This can be useful if you wish to create a trigger\nsuch as one that fires every 10 seconds until a given moment in time - rather than having to compute the number of times it would\nrepeat between the start-time and the end-time, you can simply specify the end-time and then use a repeat count of RepeatIndefinitely\n(you could even specify a repeat count of some huge number that is sure to be more than the number of times the trigger will actually\nfire before the end-time arrives).")]),t._v(" "),n("p",[t._v("SimpleTrigger instances are built using "),n("code",[t._v("TriggerBuilder")]),t._v(" (for the trigger's main properties) and "),n("code",[t._v("WithSimpleSchedule")]),t._v(" extension method\n(for the SimpleTrigger-specific properties).")]),t._v(" "),n("p",[n("strong",[t._v("Build a trigger for a specific moment in time, with no repeats:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// trigger builder creates simple trigger by default, actually an ITrigger is returned")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISimpleTrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ISimpleTrigger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myStartTime"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// some Date ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"job1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// identify job with name, group strings")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger for a specific moment in time, then repeating every ten seconds ten times:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myTimeToStartFiring"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// if a start time is not given (if this line were omitted), "now" is implied')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithRepeatCount")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// note that 10 repeats will give a total of 11 firings")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// identify job with handle to its JobDetail itself ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire once, five minutes in the future:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger5"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FutureDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" IntervalUnit"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Minute"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// use DateBuilder to create a date in the future")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// identify job with its JobKey")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire now, then repeat every five minutes, until the hour 22:00:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger7"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInMinutes")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("EndAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("DateOf")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire at the top of the next hour, then repeat every 2 hours, forever:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger8"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// because group is not specified, "trigger8" will be in the default group')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("EvenHourDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// get the next even-hour (minutes and seconds zero ("00:00"))')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInHours")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// note that in this example, 'forJob(..)' is not called ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// - which is valid if the trigger is passed to the scheduler along with the job ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("scheduleJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trigger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" job"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("Spend some time looking at all of the available methods in the language defined by "),n("code",[t._v("TriggerBuilder")]),t._v(" and its extension method "),n("code",[t._v("WithSimpleSchedule")]),t._v("\nso that you can be familiar with options available to you that may not have been demonstrated in the examples above.")]),t._v(" "),n("h2",{attrs:{id:"simpletrigger-misfire-instructions"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#simpletrigger-misfire-instructions"}},[t._v("#")]),t._v(" SimpleTrigger Misfire Instructions")]),t._v(" "),n("p",[t._v("SimpleTrigger has several instructions that can be used to inform Quartz.NET what it should do when a misfire occurs.\n(Misfire situations were introduced in the More About Triggers section of this tutorial).\nThese instructions are defined as constants on "),n("code",[t._v("MisfirePolicy.SimpleTrigger")]),t._v(" (including API documentation describing their behavior).\nThe instructions include:")]),t._v(" "),n("p",[n("strong",[t._v("Misfire Instruction Constants for SimpleTrigger")])]),t._v(" "),n("ul",[n("li",[n("code",[t._v("MisfireInstruction.IgnoreMisfirePolicy")])]),t._v(" "),n("li",[n("code",[t._v("MisfirePolicy.SimpleTrigger.FireNow")])]),t._v(" "),n("li",[n("code",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNowWithExistingRepeatCount")])]),t._v(" "),n("li",[n("code",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNowWithRemainingRepeatCount")])]),t._v(" "),n("li",[n("code",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNextWithRemainingCount")])]),t._v(" "),n("li",[n("code",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNextWithExistingCount")])])]),t._v(" "),n("p",[t._v("You should recall from the earlier lessons that all triggers have the "),n("code",[t._v("MisfirePolicy.SmartPolicy")]),t._v(" instruction available for use,\nand this instruction is also the default for all trigger types.")]),t._v(" "),n("p",[t._v("If the 'smart policy' instruction is used, SimpleTrigger dynamically chooses between its various MISFIRE instructions, based on the configuration\nand state of the given SimpleTrigger instance. The documentation for the "),n("code",[t._v("SimpleTrigger.UpdateAfterMisfire()")]),t._v(" method explains the exact details of\nthis dynamic behavior.")]),t._v(" "),n("p",[t._v("When building SimpleTriggers, you specify the misfire instruction as part of the simple schedule (via SimpleSchedulerBuilder):")]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger7"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInMinutes")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithMisfireHandlingInstructionNextWithExistingCount")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/125.1873365c.js b/assets/js/125.1873365c.js new file mode 100644 index 000000000..b162470d7 --- /dev/null +++ b/assets/js/125.1873365c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[125],{518:function(t,s,a){"use strict";a.r(s);var e=a(26),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("Listeners are objects that you create to perform actions based on events occuring within the scheduler.\nAs you can probably guess, TriggerListeners receive events related to triggers, and JobListeners receive events related to jobs.")]),t._v(" "),a("p",[t._v('Trigger-related events include: trigger firings, trigger mis-firings (discussed in the "Triggers" section of this document),\nand trigger completions (the jobs fired off by the trigger is finished).')]),t._v(" "),a("div",{staticClass:"custom-block danger"},[a("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),a("p",[t._v("Make sure your trigger and job listeners never throw an exception (use a try-catch) and that they can handle internal problems.\nJobs can get stuck after Quartz is unable to determine whether required logic in listener was completed successfully when listener notification failed.")])]),t._v(" "),a("p",[a("strong",[t._v("The ITriggerListener Interface")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITriggerListener")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerFired")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("VetoJobExecution")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerMisfired")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerComplete")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")])]),t._v(" triggerInstructionCode"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Job-related events include: a notification that the job is about to be executed, and a notification when the job has completed execution.")]),t._v(" "),a("p",[a("strong",[t._v("The IJobListener Interface")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobListener")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobToBeExecuted")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobExecutionVetoed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("Task")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobWasExecuted")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionException")]),t._v(" jobException"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),a("h2",{attrs:{id:"using-your-own-listeners"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-your-own-listeners"}},[t._v("#")]),t._v(" Using Your Own Listeners")]),t._v(" "),a("p",[t._v("To create a listener, simply create an object the implements either the "),a("code",[t._v("ITriggerListener")]),t._v(" and/or "),a("code",[t._v("IJobListener")]),t._v(" interface.\nListeners are then registered with the scheduler during run time, and must be given a name (or rather, they must advertise their own\nname via their Name property.")]),t._v(" "),a("p",[t._v("For your convenience, rather than implementing those interfaces, your class could also extend the class "),a("code",[t._v("JobListenerSupport")]),t._v(" or "),a("code",[t._v("TriggerListenerSupport")]),t._v("\nand simply override the events you're interested in.")]),t._v(" "),a("p",[t._v("Listeners are registered with the scheduler's "),a("code",[t._v("ListenerManager")]),t._v(" along with a Matcher that describes which Jobs/Triggers the listener wants to receive events for.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),a("p",[t._v("Listeners are registered with the scheduler during run time, and are "),a("strong",[t._v("NOT")]),t._v(" stored in the JobStore along with the jobs and triggers.\nThis is because listeners are typically an integration point with your application.\nHence, each time your application runs, the listeners need to be re-registered with the scheduler.")])]),t._v(" "),a("p",[a("strong",[t._v("Adding a JobListener that is interested in a particular job:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" KeyMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("KeyEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobKey")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobName"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Adding a JobListener that is interested in all jobs of a particular group:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GroupEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Adding a JobListener that is interested in all jobs of two particular groups:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tOrMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Or")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GroupEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GroupEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"yourGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Adding a JobListener that is interested in all jobs:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AnyGroup")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Listeners are not used by most users of Quartz.NET, but are handy when application requirements create the need\nfor the notification of events, without the Job itself explicitly notifying the application.")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/126.2b8c172b.js b/assets/js/126.2b8c172b.js new file mode 100644 index 000000000..b86a3d7cc --- /dev/null +++ b/assets/js/126.2b8c172b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[126],{497:function(t,s,a){"use strict";a.r(s);var n=a(26),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("Before you can use the scheduler, it needs to be instantiated (who'd have guessed?).\nTo do this, you use an implementor of ISchedulerFactory.")]),t._v(" "),a("p",[t._v("Once a scheduler is instantiated, it can be started, placed in stand-by mode, and shutdown.\nNote that once a scheduler is shutdown, it cannot be restarted without being re-instantiated.\nTriggers do not fire (jobs do not execute) until the scheduler has been started, nor while it is\nin the paused state.")]),t._v(" "),a("p",[t._v("Here's a quick snippet of code, that instantiates and starts a scheduler, and schedules a job for execution:")]),t._v(" "),a("p",[a("strong",[t._v("Using Quartz.NET")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// construct a scheduler factory using defaults")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StdSchedulerFactory")]),t._v(" factory "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get a scheduler")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" scheduler "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" factory"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetScheduler")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then every 40 seconds")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("40")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You could also schedule multiple triggers for the same job with")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// await scheduler.ScheduleJob(job, new List() { trigger1, trigger2 }, replace: true);")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Configuring scheduler with fluent API")])]),t._v(" "),a("p",[t._v("You can also use SchedulerBuilder fluent API to programmatically configure different aspects of the scheduler.")]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" sched "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" SchedulerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// default max concurrency is 10")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseDefaultThreadPool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MaxConcurrency "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this is the default ")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .WithMisfireThreshold(TimeSpan.FromSeconds(60))")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsePersistentStore")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// force job data map values to be considered as strings")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// prevents nasty surprises if object is accidentally serialized and then ")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// serialization format breaks, defaults to false")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UseProperties "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseClustering")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseSqlServer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my connection string"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this requires Quartz.Serialization.Json NuGet package")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseJsonSerializer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// job initialization plugin handles our xml reading, without it defaults are used")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// requires Quartz.Plugins NuGet package")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UseXmlSchedulingConfiguration")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Files "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"~/quartz_jobs.xml"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this is the default")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FailOnFileNotFound "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// this is not the default")]),t._v("\n x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FailOnSchedulingError "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("BuildScheduler")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("As you can see, working with Quartz.NET is rather simple. In "),a("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/jobs-and-triggers.html"}},[t._v("Lesson 2")]),t._v(" we'll give a quick overview of Jobs and Triggers, so that you can more fully understand this example.")],1)])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/127.ce06c938.js b/assets/js/127.ce06c938.js new file mode 100644 index 000000000..7a2886afc --- /dev/null +++ b/assets/js/127.ce06c938.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[127],{498:function(e,t,a){"use strict";a.r(t);var r=a(26),n=Object(r.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("p",[e._v("You can install Quartz and related packages using "),a("a",{attrs:{href:"https://www.nuget.org/packages/Quartz",target:"_blank",rel:"noopener noreferrer"}},[e._v("NuGet"),a("OutboundLink")],1)]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("Install-Package Quartz\n")])])]),a("p",[e._v("or you can download the "),a("a",{attrs:{href:"https://github.com/quartznet/quartznet/releases",target:"_blank",rel:"noopener noreferrer"}},[e._v("ZIP from GitHub releases"),a("OutboundLink")],1),e._v(" which also contains source code and examples.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/128.853bfa59.js b/assets/js/128.853bfa59.js new file mode 100644 index 000000000..17ad49e31 --- /dev/null +++ b/assets/js/128.853bfa59.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[128],{499:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/129.a07b8371.js b/assets/js/129.a07b8371.js new file mode 100644 index 000000000..f8c472816 --- /dev/null +++ b/assets/js/129.a07b8371.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[129],{500:function(e,t,i){"use strict";i.r(t);var a=i(26),n=Object(a.a)({},(function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[i("h2",{attrs:{id:"runtime-environments"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#runtime-environments"}},[e._v("#")]),e._v(" Runtime Environments")]),e._v(" "),i("ul",[i("li",[e._v("Quartz.NET can run embedded within another free standing application")]),e._v(" "),i("li",[e._v("Quartz.NET can run as a stand-alone program (within its own .NET virtual machine instance), to be used via .NET Remoting")]),e._v(" "),i("li",[e._v("Quartz.NET can be instantiated as a cluster of stand-alone programs (with load-balance and fail-over capabilities)")])]),e._v(" "),i("h2",{attrs:{id:"job-scheduling"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#job-scheduling"}},[e._v("#")]),e._v(" Job Scheduling")]),e._v(" "),i("p",[e._v("Jobs are scheduled to run when a given Trigger occurs. Triggers can be created with nearly any combination of the following directives:")]),e._v(" "),i("ul",[i("li",[e._v("at a certain time of day (to the millisecond)")]),e._v(" "),i("li",[e._v("on certain days of the week")]),e._v(" "),i("li",[e._v("on certain days of the month")]),e._v(" "),i("li",[e._v("on certain days of the year")]),e._v(" "),i("li",[e._v("not on certain days listed within a registered Calendar (such as business holidays)")]),e._v(" "),i("li",[e._v("repeated a specific number of times")]),e._v(" "),i("li",[e._v("repeated until a specific time/date")]),e._v(" "),i("li",[e._v("repeated indefinitely")]),e._v(" "),i("li",[e._v("repeated with a delay interval")])]),e._v(" "),i("p",[e._v("Jobs are given names by their creator and can also be organized into named groups.\nTriggers may also be given names and placed into groups, in order to easily organize them within the scheduler.\nJobs can be added to the scheduler once, but registered with multiple Triggers.")]),e._v(" "),i("h2",{attrs:{id:"job-execution"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#job-execution"}},[e._v("#")]),e._v(" Job Execution")]),e._v(" "),i("ul",[i("li",[e._v("Jobs can be any .NET class that implements the simple IJob interface, leaving infinite possibilities for the work Jobs can perform.")]),e._v(" "),i("li",[e._v("Job class instances can be instantiated by Quartz.NET, or by your application's framework.")]),e._v(" "),i("li",[e._v("When a Trigger occurs, the scheduler notifies zero or more .NET objects implementing the JobListener and TriggerListener interfaces.\tThese listeners are also notified after the Job has executed.")]),e._v(" "),i("li",[e._v("As Jobs are completed, they return a JobCompletionCode which informs the scheduler of success or failure. The JobCompletionCode can also instruct the scheduler of any actions it should take based on the success/fail code - such as immediate re-execution of the Job.")])]),e._v(" "),i("h2",{attrs:{id:"job-persistence"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#job-persistence"}},[e._v("#")]),e._v(" Job Persistence")]),e._v(" "),i("ul",[i("li",[e._v("The design of Quartz.NET includes a IJobStore interface that can be implemented to provide various mechanisms for the storage of jobs.")]),e._v(" "),i("li",[e._v('With the use of the included AdoJobStore, all Jobs and Triggers configured as "non-volatile" are stored in a relational database via ADO.NET.')]),e._v(" "),i("li",[e._v("With the use of the included RAMJobStore, all Jobs and Triggers are stored in RAM and therefore do not persist between program executions - but this has the advantage of not requiring an external database.")])]),e._v(" "),i("h2",{attrs:{id:"clustering"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#clustering"}},[e._v("#")]),e._v(" Clustering")]),e._v(" "),i("ul",[i("li",[e._v("Fail-over.")]),e._v(" "),i("li",[e._v("Load balancing.")])]),e._v(" "),i("h2",{attrs:{id:"listeners-plug-ins"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#listeners-plug-ins"}},[e._v("#")]),e._v(" Listeners & Plug-Ins")]),e._v(" "),i("ul",[i("li",[e._v("Applications can catch scheduling events to monitor or control job/trigger behavior by implementing one or more listener interfaces.")]),e._v(" "),i("li",[e._v("The Plug-In mechanism can be used add functionality to Quartz, such keeping a history of job executions, or loading job and trigger definitions from a file.")]),e._v(" "),i("li",[e._v('Quartz ships with a number of "factory built" plug-ins and listeners.')])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/13.c53349db.js b/assets/js/13.c53349db.js new file mode 100644 index 000000000..1d2b4850e --- /dev/null +++ b/assets/js/13.c53349db.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{382:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(26),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); \ No newline at end of file diff --git a/assets/js/130.0feef69a.js b/assets/js/130.0feef69a.js new file mode 100644 index 000000000..9851f0344 --- /dev/null +++ b/assets/js/130.0feef69a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[130],{501:function(e,t,s){"use strict";s.r(t);var a=s(26),r=Object(a.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("h1",{attrs:{id:"license"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#license"}},[e._v("#")]),e._v(" License")]),e._v(" "),s("p",[e._v("Quartz.NET is licensed under the terms of the Apache License, Version 2.0.")]),e._v(" "),s("p",[s("a",{attrs:{href:"http://www.apache.org/licenses/LICENSE-2.0"}},[e._v("http://www.apache.org/licenses/LICENSE-2.0")]),e._v("\n("),s("a",{attrs:{href:"http://www.apache.org/licenses/LICENSE-2.0.txt"}},[e._v("TXT")]),e._v(" or "),s("a",{attrs:{href:"http://www.apache.org/licenses/LICENSE-2.0.html"}},[e._v("HTML")]),e._v(")")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/131.c5fcddc7.js b/assets/js/131.c5fcddc7.js new file mode 100644 index 000000000..0a4b71c95 --- /dev/null +++ b/assets/js/131.c5fcddc7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[131],{502:function(t,e,r){"use strict";r.r(e);var a=r(26),s=Object(a.a)({},(function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"quartz-net-mailing-list"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#quartz-net-mailing-list"}},[t._v("#")]),t._v(" Quartz.NET Mailing List")]),t._v(" "),r("p",[t._v("Quartz.NET mailing list is currently operated on "),r("a",{attrs:{href:"http://groups.google.com/group/quartznet"}},[t._v("Google Groups")]),t._v(".")]),t._v(" "),r("p",[t._v("Please send your questions and other ideas here so we share them with everybody.")]),t._v(" "),r("div",{attrs:{align:"center"}},[r("form",{attrs:{action:"http://groups.google.com/group/quartznet/boxsubscribe"}},[r("table",{staticStyle:{"background-color":"#fff",padding:"5px"},attrs:{border:"0",cellspacing:"0"}},[r("tr",[r("td",{staticStyle:{"padding-left":"5px"}},[r("b",[t._v("Subscribe to Quartz.NET")])])]),t._v(" "),r("input",{attrs:{type:"hidden",name:"hl",value:"en"}}),t._v(" "),r("tr",[r("td",{staticStyle:{"padding-left":"5px"}},[t._v("\n\t\t\t\t\t\tEmail: "),r("input",{attrs:{type:"text",name:"email"}}),t._v(" "),r("input",{attrs:{type:"submit",name:"sub",value:"Subscribe"}})])]),t._v(" "),r("tr",[r("td",{attrs:{align:"right"}},[r("a",{attrs:{href:"http://groups.google.com/group/quartznet?hl=en"}},[t._v("Visit this group")])])])])])])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/132.13fbd625.js b/assets/js/132.13fbd625.js new file mode 100644 index 000000000..49d4ddd4a --- /dev/null +++ b/assets/js/132.13fbd625.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[132],{503:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/133.f3d14f4d.js b/assets/js/133.f3d14f4d.js new file mode 100644 index 000000000..4b3585a22 --- /dev/null +++ b/assets/js/133.f3d14f4d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[133],{504:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/134.320abb38.js b/assets/js/134.320abb38.js new file mode 100644 index 000000000..84f0d8e77 --- /dev/null +++ b/assets/js/134.320abb38.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[134],{505:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/135.be16f19a.js b/assets/js/135.be16f19a.js new file mode 100644 index 000000000..329802099 --- /dev/null +++ b/assets/js/135.be16f19a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[135],{506:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/136.de2948c9.js b/assets/js/136.de2948c9.js new file mode 100644 index 000000000..ad1f6400d --- /dev/null +++ b/assets/js/136.de2948c9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[136],{507:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/137.52cca593.js b/assets/js/137.52cca593.js new file mode 100644 index 000000000..6392e5bff --- /dev/null +++ b/assets/js/137.52cca593.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[137],{508:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/138.272768ba.js b/assets/js/138.272768ba.js new file mode 100644 index 000000000..0290f459b --- /dev/null +++ b/assets/js/138.272768ba.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[138],{509:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/139.cb00fd64.js b/assets/js/139.cb00fd64.js new file mode 100644 index 000000000..c33fcb371 --- /dev/null +++ b/assets/js/139.cb00fd64.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[139],{510:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/14.6535f905.js b/assets/js/14.6535f905.js new file mode 100644 index 000000000..787d5cef0 --- /dev/null +++ b/assets/js/14.6535f905.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{388:function(t,s,e){"use strict";e.r(s);var a=e(26),r=Object(a.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("p",[this._v("Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems.")]),this._v(" "),s("h3",{attrs:{id:"latest-news"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#latest-news"}},[this._v("#")]),this._v(" Latest News")]),this._v(" "),s("BlogExcerpt")],1)}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/140.e168ce8e.js b/assets/js/140.e168ce8e.js new file mode 100644 index 000000000..0bec1bb38 --- /dev/null +++ b/assets/js/140.e168ce8e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[140],{511:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/141.66280f26.js b/assets/js/141.66280f26.js new file mode 100644 index 000000000..f042af66d --- /dev/null +++ b/assets/js/141.66280f26.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[141],{512:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/142.2f9f56f4.js b/assets/js/142.2f9f56f4.js new file mode 100644 index 000000000..64b27de35 --- /dev/null +++ b/assets/js/142.2f9f56f4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[142],{513:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/143.35b86cf0.js b/assets/js/143.35b86cf0.js new file mode 100644 index 000000000..d89e2d632 --- /dev/null +++ b/assets/js/143.35b86cf0.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[143],{514:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/144.419ebf8f.js b/assets/js/144.419ebf8f.js new file mode 100644 index 000000000..c9d6d057e --- /dev/null +++ b/assets/js/144.419ebf8f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[144],{515:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/145.4e24e5c4.js b/assets/js/145.4e24e5c4.js new file mode 100644 index 000000000..21d5461fa --- /dev/null +++ b/assets/js/145.4e24e5c4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[145],{516:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/146.ec8464bd.js b/assets/js/146.ec8464bd.js new file mode 100644 index 000000000..3580a8dcb --- /dev/null +++ b/assets/js/146.ec8464bd.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[146],{517:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/15.e0899e5a.js b/assets/js/15.e0899e5a.js new file mode 100644 index 000000000..557d98b3f --- /dev/null +++ b/assets/js/15.e0899e5a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{389:function(e,t,r){"use strict";r.r(t);var a=r(26),o=Object(a.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("Quartz.NET 2.0 has finally been released. Quartz.NET 2.0 introduces a new more interfaced based model of operating with the API, lots of performance improvements and bug fixes to issues found in 1.0.x line.")]),e._v(" "),r("p",[r("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),r("ul",[r("li",[e._v(".NET 1.1 and 2.0 support is dropped")]),e._v(" "),r("li",[e._v("Quartz.NET now needs .NET version 3.5 SP1 or later to run due to use of new language features and classes")]),e._v(" "),r("li",[e._v("Many public interface methods have changed from returning arrays to generic IList or ISet interfaces")]),e._v(" "),r("li",[e._v("TriggerBuilder implementations and JobBuilder should now be used to create different job and trigger definitions")]),e._v(" "),r("li",[e._v("Introduced IJobDetail, IContrigger, ISimpleTrigger, ICalendarIntervalTrigger have far less members and especially mutators")]),e._v(" "),r("li",[e._v("When C5 collections were introduced as set-based implementation provider, ISet and ISortedSet interfaces were narrowed (IList inheritance removed)")]),e._v(" "),r("li",[e._v("string triggerName, string triggerGroup are now encapsulated in TriggerKey (has the same fields)")]),e._v(" "),r("li",[e._v("string jobName, string jobGroup are now encapsulated in JobKey (has the same fields)")]),e._v(" "),r("li",[e._v("JobInitializationPlugin is now deprecated in favor of XMLSchedulingDataProcessorPlugin, JobInitializationPlugin no longer included")]),e._v(" "),r("li",[e._v("Microsoft's Oracle drivers are no longer supported, use 10g or 11g ODP.NET drivers")]),e._v(" "),r("li",[e._v("Database schema has changed, you need to convert your 1.x schema to new version, sample migration script available in database folder")])]),e._v(" "),r("p",[r("strong",[e._v("OTHER NOTABLE CHANGES")])]),e._v(" "),r("ul",[r("li",[e._v("XMLSchedulingDataProcessorPlugin uses new XML format that allows more control over triggers but no support for calendars")]),e._v(" "),r("li",[e._v("There are extension methods for the new trigger builder that allow you to set trigger specifics")]),e._v(" "),r("li",[e._v("Client Profile is now supported and there are now separate DLLs for client profile")]),e._v(" "),r("li",[e._v("PropertySettingJobFactory is now the default JobFactory")])]),e._v(" "),r("p",[e._v("Please see the "),r("a",{attrs:{href:"https://raw.github.com/quartznet/quartznet/master/changelog.txt",target:"_blank",rel:"noopener noreferrer"}},[e._v("change log"),r("OutboundLink")],1),e._v(" for complete list of changes.")]),e._v(" "),r("p",[e._v("Quartz.NET is also available as NuGet package. You can install it with command:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",[r("code",[e._v("Install-Package Quartz\n")])])]),r("p",[e._v("This version corresponds to Java Quartz's version 2.1.")]),e._v(" "),r("p",[e._v("Big thanks to Quartz.NET community that has sumbitted pull requests, patches, bug reports and for being so active and making the 2.0 release possible!")]),e._v(" "),r("p",[e._v("There's a first version of "),r("RouterLink",{attrs:{to:"/documentation/quartz-2.x/migration-guide.html"}},[e._v("migration guide")]),e._v(" but the tutorial hasn't been updated yet. You can also always check "),r("a",{attrs:{href:"http://www.quartz-scheduler.org/documentation",target:"_blank",rel:"noopener noreferrer"}},[e._v("Java Quartz's documentation"),r("OutboundLink")],1),e._v(".")],1),e._v(" "),r("Download")],1)}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/16.5066eada.js b/assets/js/16.5066eada.js new file mode 100644 index 000000000..c066504d7 --- /dev/null +++ b/assets/js/16.5066eada.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{390:function(e,t,n){"use strict";n.r(t);var i=n(26),l=Object(i.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("p",[e._v("This is a maintenance release containing a critical fix to Oracle job store support.")]),e._v(" "),n("p",[n("strong",[e._v("FIXES")])]),e._v(" "),n("ul",[n("li",[e._v("Oracle database support broken")]),e._v(" "),n("li",[e._v("Incorrect .NET 4.5 requirement in 4.0 build (only NuGet affected)")]),e._v(" "),n("li",[e._v("XML validation fails as schema not embedded (only NuGet affected)")]),e._v(" "),n("li",[e._v("ObjectUtils.SetPropertyValue fails with explicitly implemented interface members")])]),e._v(" "),n("Download")],1)}),[],!1,null,null,null);t.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/17.2cd0575f.js b/assets/js/17.2cd0575f.js new file mode 100644 index 000000000..a7c1f7c04 --- /dev/null +++ b/assets/js/17.2cd0575f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{391:function(e,n,r){"use strict";r.r(n);var i=r(26),o=Object(i.a)({},(function(){var e=this,n=e.$createElement,r=e._self._c||n;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("To welcome year 2013 we are releasing new and improved version of Quart.NET!\nThis release contains important bug fixes, new functionality and minor breaking changes.")]),e._v(" "),r("ul",[r("li",[e._v("C5 depedency is now internalized and allows you to use whatever version you want outside of Quartz.")]),e._v(" "),r("li",[e._v("Custom IJobFactory implementations now need to implement new method void ReturnJob(IJob job) for container managed cleanup.")]),e._v(" "),r("li",[e._v("NthIncludedDayTrigger was removed as it was accidentally left behind even though being legacy and replaced by DailyTimeIntervalTrigger.")])]),e._v(" "),r("p",[r("strong",[e._v("NEW FEATURES")])]),e._v(" "),r("ul",[r("li",[e._v("TimeZone support for calendars / Andrew Smith")]),e._v(" "),r("li",[e._v("Allow scheduling relative to replaced trigger with XML configuration")]),e._v(" "),r("li",[e._v("Add method to IJobFactory to destroy a job instance created by the factory breaking / minor breaking, added new required method")]),e._v(" "),r("li",[e._v("Internalize C5 dependency")]),e._v(" "),r("li",[e._v("Support for Oracle ODP 11.2 Release 4")]),e._v(" "),r("li",[e._v("Upgrade SQLite dependency to version 1.0.83")]),e._v(" "),r("li",[e._v("Upgrade to Common.Logging 2.1.2")])]),e._v(" "),r("p",[r("strong",[e._v("FIXES")])]),e._v(" "),r("ul",[r("li",[e._v("Scheduled Shutdown blocked even if waitForJobsToComplete is false")]),e._v(" "),r("li",[e._v("DailyTimeIntervalTriggerImpl should be serializable")]),e._v(" "),r("li",[e._v('InstanceID = "AUTO" may cause "String or binary data would be truncated" error on qrtz_fired_triggers.entry_id')]),e._v(" "),r("li",[e._v("PlugInExample doesn't execute any jobs")]),e._v(" "),r("li",[e._v("Recovering triggers have empty/incorrect JobDataMap")]),e._v(" "),r("li",[e._v("Make Quartz.NET work under medium trust when running .NET 3.5")]),e._v(" "),r("li",[e._v("tables_oracle.sql uses deprecated VARCHAR type")]),e._v(" "),r("li",[e._v("Improve error reporting for database connection failure")]),e._v(" "),r("li",[e._v("Scheduler Shutdown Freezes when There are Jobs Still Running")]),e._v(" "),r("li",[e._v("Use System.Version instead of FileVersionInfo to retive current Quartz version")]),e._v(" "),r("li",[e._v("DailyTimeIntervalTriggerImpl Validate broken")])]),e._v(" "),r("p",[r("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),r("ul",[r("li",[e._v("Remove NthIncludedDayTrigger that was supposed to be removed in 2.0")]),e._v(" "),r("li",[e._v("Remove Visual Studio 2008 solutions and projects")]),e._v(" "),r("li",[e._v("Add support for DateTimeOffset and TimeSpan to JobDataMap / minor breaking - cleanup of API")])]),e._v(" "),r("p",[e._v("Special thanks to Andrew Smith for working hard on TimeZone support. Credits go also to our vibrant community actively helping on mailing list and reporting issues and creating pull requests.")]),e._v(" "),r("Download")],1)}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/18.729d30ae.js b/assets/js/18.729d30ae.js new file mode 100644 index 000000000..120dcfdb1 --- /dev/null +++ b/assets/js/18.729d30ae.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{392:function(t,s,e){"use strict";e.r(s);var n=e(26),i=Object(n.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("p",[this._v("This is a maintenance release containing strongly singed dlls.")]),this._v(" "),s("p",[s("strong",[this._v("FIXES")])]),this._v(" "),s("ul",[s("li",[this._v("assemblies are missing strong name due to error in ilmerge parameters")])]),this._v(" "),s("Download")],1)}),[],!1,null,null,null);s.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/19.e79f2201.js b/assets/js/19.e79f2201.js new file mode 100644 index 000000000..1709b7df4 --- /dev/null +++ b/assets/js/19.e79f2201.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{393:function(e,t,i){"use strict";i.r(t);var s=i(26),n=Object(s.a)({},(function(){var e=this.$createElement,t=this._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("p",[this._v("This is a maintenance release fixing issue where .NET 4.0 DLLs required 4.5 runtime due to ilmerge missing special framework parameter.")]),this._v(" "),t("p",[t("strong",[this._v("FIXES")])]),this._v(" "),t("ul",[t("li",[this._v("TypeLoadException: Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' with .NET 4.0")])]),this._v(" "),t("Download")],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/20.649245c0.js b/assets/js/20.649245c0.js new file mode 100644 index 000000000..7464532a0 --- /dev/null +++ b/assets/js/20.649245c0.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{394:function(e,t,r){"use strict";r.r(t);var o=r(26),i=Object(o.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("This release contains important bug fixes, new functionality and minor breaking changes.")]),e._v(" "),r("p",[r("strong",[e._v("UPGRADING")])]),e._v(" "),r("p",[e._v("Please examine and run the database\\schema_20_to_22_upgrade.sql script if you are using AdoJobStore\nthis script adds a new column SCHED_TIME to table QRTZ_FIRED_TRIGGERS\nfile contains the alter command for SQL Server and other database samples in comments")]),e._v(" "),r("p",[r("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),r("ul",[r("li",[e._v("database schema needs upgrade")]),e._v(" "),r("li",[e._v("add SchedulerStarting() method to ISchedulerListener interface")]),e._v(" "),r("li",[e._v("make the scheduler's TypeLoadHelper available to plugins when they are initialized")]),e._v(" "),r("li",[e._v("dbFailureRetryInterval parameter was removed from DirectSchedulerFactory APIs")])]),e._v(" "),r("p",[r("strong",[e._v("NEW FEATURES")])]),e._v(" "),r("ul",[r("li",[e._v("ability to override worker thread names (when using SimpleThreadPool)")]),e._v(" "),r("li",[e._v("add new IScheduler method: ScheduleJob(IJobDetail job, ISet trigger) to schedule multiple triggers for a job all at once")]),e._v(" "),r("li",[e._v("allow 'triggerless' initial storing of non-durable jobs.")]),e._v(" "),r("li",[e._v("improvements for job recovery information")]),e._v(" "),r("li",[e._v("package job_scheduling_data_2_0.xsd to nuget package's content folder")]),e._v(" "),r("li",[e._v("allow scheduler exported with remoting to be used from local machine only")]),e._v(" "),r("li",[e._v("support for Oracle managed ODP driver")])]),e._v(" "),r("p",[r("strong",[e._v("FIXES")])]),e._v(" "),r("ul",[r("li",[e._v("job ending with exception and trigger not going to fire again, trigger is incorrectly not removed from job store")]),e._v(" "),r("li",[e._v("XML schema supports multiple schedule elements but processor does not")]),e._v(" "),r("li",[e._v("DailyTimeIntervalTriggerPersistenceDelegate does not handle empty time interval properly")]),e._v(" "),r("li",[e._v("DailyTimeIntervalScheduleBuilder.EndingDailyAfterCount(...) doesn't pass validation")]),e._v(" "),r("li",[e._v("trace throwing exception")]),e._v(" "),r("li",[e._v("bug in QuartzSchedulerThread.GetRandomizedIdleWaitTime()")]),e._v(" "),r("li",[e._v("can't delete or replace job without the referenced class")])]),e._v(" "),r("p",[r("strong",[e._v("MISC")])]),e._v(" "),r("ul",[r("li",[e._v("Performance improvements, including improvements to some select statements in AdoJobStore")])]),e._v(" "),r("Download")],1)}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/21.1a3614c5.js b/assets/js/21.1a3614c5.js new file mode 100644 index 000000000..37f6bc60e --- /dev/null +++ b/assets/js/21.1a3614c5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{395:function(e,t,r){"use strict";r.r(t);var i=r(26),o=Object(i.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("This is a minor release containing mostly bug fixes.")]),e._v(" "),r("p",[r("strong",[e._v("NEW FEATURES")])]),e._v(" "),r("ul",[r("li",[e._v("GroupMatcher.AnyGroup() support")]),e._v(" "),r("li",[e._v("Add network credential and SMTP port definition support to SendMailJob")])]),e._v(" "),r("p",[r("strong",[e._v("FIXES")])]),e._v(" "),r("ul",[r("li",[e._v("SchedulerException constructor unnecessarily uses Exception.ToString as message")]),e._v(" "),r("li",[e._v("Thread name prefix for thread pool is not set")]),e._v(" "),r("li",[e._v("Triggers should not be excluded based on the fire time of the first selected trigger")]),e._v(" "),r("li",[e._v("Quarts server does not properly log possible exception when starting the service")]),e._v(" "),r("li",[e._v("DailyTimeIntervalTrigger GetFireTimeAfter produces incorrect result when date is in the past")]),e._v(" "),r("li",[e._v("batchTriggerAcquisitionMaxCount acquires one trigger unless batchTriggerAcquisitionFireAheadTimeWindow is also set")]),e._v(" "),r("li",[e._v("Oracle ODP Managed provider should set BindByName to true for OracleCommands")])]),e._v(" "),r("Download")],1)}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/22.8a66bf8f.js b/assets/js/22.8a66bf8f.js new file mode 100644 index 000000000..def4720d6 --- /dev/null +++ b/assets/js/22.8a66bf8f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{396:function(t,e,s){"use strict";s.r(e);var n=s(26),o=Object(n.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("p",[this._v("The whole website has moved to using GitHub pages. It should be now easier to contribute to documentation, the tutorial for version 2.x is currently in the works so stay tuned. You can fork and create pull requests from the "),e("a",{attrs:{href:"https://github.com/quartznet/quartznet/tree/gh-pages",target:"_blank",rel:"noopener noreferrer"}},[this._v("gh-pages branch of the repository"),e("OutboundLink")],1),this._v(".")]),this._v(" "),e("p",[this._v("There still might be some small glitches with links and content.")])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/23.e7ae5d25.js b/assets/js/23.e7ae5d25.js new file mode 100644 index 000000000..b7babb36e --- /dev/null +++ b/assets/js/23.e7ae5d25.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{397:function(t,e,n){"use strict";n.r(e);var s=n(26),o=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("p",[this._v("With the latest switch to GitHub Pages it's been a joy to create content. There tutorial has now been split\nto two separate tutorials for Quartz.NET 1.x and 2.x respectively.")]),this._v(" "),e("p",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/index.html"}},[this._v("Check the new tutorial with the 2.x API changes")])],1)])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/24.cde296f3.js b/assets/js/24.cde296f3.js new file mode 100644 index 000000000..4937470eb --- /dev/null +++ b/assets/js/24.cde296f3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{398:function(e,t,i){"use strict";i.r(t);var n=i(26),r=Object(n.a)({},(function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[i("p",[e._v("This is a minor release fixing couple of minor bugs.")]),e._v(" "),i("p",[i("strong",[e._v("FIXES")])]),e._v(" "),i("ul",[i("li",[e._v("long properties incorrectly read as int in SimplePropertiesTriggerPersistenceDelegateSupport")]),e._v(" "),i("li",[e._v("RecoveringTriggerKey in JobExecutionContext has group and name wrong way around")]),e._v(" "),i("li",[e._v("Make SQL Server table create script Azure SQL compliant")]),e._v(" "),i("li",[e._v("Add missing clustered index for QRTZ_BLOB_TRIGGERS table\n** You need to manually add this to existing installation (tables created with old script), see ALTER TABLE [dbo].QRTZ_BLOB_TRIGGERS WITH NOCHECK ADD... in script")])]),e._v(" "),i("Download")],1)}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/25.346eb63b.js b/assets/js/25.346eb63b.js new file mode 100644 index 000000000..f45882fd5 --- /dev/null +++ b/assets/js/25.346eb63b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{399:function(e,t,o){"use strict";o.r(t);var r=o(26),n=Object(r.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("This is a bug fix release which has some critical fixes, especially for CalendarIntevalTrigger\nfuture date calculation and trigger's next fires not being processed in a timely fashion when AdoJobStore is used\nwith DisallowConcurrentExecutionAttribute and trigger has short repeat interval.")]),e._v(" "),o("p",[e._v("This update is highly recommended for all users.")]),e._v(" "),o("p",[o("strong",[e._v("FIXES")])]),e._v(" "),o("ul",[o("li",[e._v("StdAdoConstants.SqlSelectSchedulerStates does not filter on the SCHED_NAME column")]),e._v(" "),o("li",[e._v("CalendarIntervalTrigger produces incorrect schedule")]),e._v(" "),o("li",[e._v("Trigger completion signaling from AdoJobStore does not work properly when DisallowConcurrentExecution is set")])]),e._v(" "),o("p",[o("strong",[e._v("NEW FEATURES")])]),e._v(" "),o("ul",[o("li",[e._v("IDisposable jobs should be disposed after execution")]),e._v(" "),o("li",[e._v("Support for defining DbMetadata via App.config's quartz section")])]),e._v(" "),o("Download")],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/26.4a2442fe.js b/assets/js/26.4a2442fe.js new file mode 100644 index 000000000..a7e132abd --- /dev/null +++ b/assets/js/26.4a2442fe.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{400:function(e,t,s){"use strict";s.r(t);var i=s(26),n=Object(i.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("p",[e._v("This is a bug fix release addressing some minor issues.")]),e._v(" "),s("p",[s("strong",[e._v("FIXES")])]),e._v(" "),s("ul",[s("li",[e._v("Cannot register trigger persistence delegates with assembly qualified names")]),e._v(" "),s("li",[e._v("Set example server's current directory to the one where server.exe is")]),e._v(" "),s("li",[e._v("Fix TimeZoneInfo.GetUtcOffset(DateTimeOffset dateTimeOffset) not implemented in Mono")]),e._v(" "),s("li",[e._v("Gracefully handle mixed useProperties usage when reading from DB when useproperties value has changed")]),e._v(" "),s("li",[e._v("FindSystemTimeZoneById should work with both 'Coordinated Universal Time' and 'UTC'")]),e._v(" "),s("li",[e._v("Latest release (2.2.3) didn't include Dbprovider constant string in StdSchedulerFactory - running examples fails")])]),e._v(" "),s("Download")],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/27.1ced7f91.js b/assets/js/27.1ced7f91.js new file mode 100644 index 000000000..e52e21a63 --- /dev/null +++ b/assets/js/27.1ced7f91.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{401:function(e,i,t){"use strict";t.r(i);var r=t(26),n=Object(r.a)({},(function(){var e=this,i=e.$createElement,t=e._self._c||i;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("This is a bug fix release with some changes that warrant a minor version increment.")]),e._v(" "),t("p",[t("strong",[e._v("NEW FEATURE")])]),e._v(" "),t("ul",[t("li",[e._v("Upgrade to Common.Logging 2.3.1")]),e._v(" "),t("li",[e._v("Add ability to check if calendar exists in job store")]),e._v(" "),t("li",[e._v("Add FirebirdDelegate and update Firebird driver")])]),e._v(" "),t("p",[t("strong",[e._v("FIXES")])]),e._v(" "),t("ul",[t("li",[e._v("DailyTimeIntervalTriggerImpl fires twice during daylight saving time day")]),e._v(" "),t("li",[e._v("No wait time between db connection failures with AcquireNextTriggers causes excessive logging")]),e._v(" "),t("li",[e._v("Configure the quartz server in the "),t("code",[e._v("")]),e._v(" section fails")]),e._v(" "),t("li",[e._v("CronExpression ctor incorrectly uses the non-uppercased string")]),e._v(" "),t("li",[e._v("Triggers fired milliseconds too early")]),e._v(" "),t("li",[e._v("Loading of Quartz 4.0 DLL fails on systems with no .NET 4.5 installed")])]),e._v(" "),t("Download")],1)}),[],!1,null,null,null);i.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/28.8cf196b8.js b/assets/js/28.8cf196b8.js new file mode 100644 index 000000000..de331d425 --- /dev/null +++ b/assets/js/28.8cf196b8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{402:function(e,t,o){"use strict";o.r(t);var r=o(26),i=Object(r.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("This is a bug fix release with upgraded Common.Logging dependency, also problems running\nunder .NET 4.0 should now be finally fixed.")]),e._v(" "),o("p",[o("strong",[e._v("NEW FEATURE")])]),e._v(" "),o("ul",[o("li",[e._v("Upgrade to Common.Logging 3.0.0")])]),e._v(" "),o("p",[o("strong",[e._v("FIXES")])]),e._v(" "),o("ul",[o("li",[e._v("JobDetailImpl members should be virtual")]),e._v(" "),o("li",[e._v("Triggers do not transition to error state in AdoJobStore when job retrieval fails during trigger acquisition")]),e._v(" "),o("li",[e._v("Quartz.Server.exe.config refers to wrong Common.Logging.Log4Net assembly")]),e._v(" "),o("li",[e._v("Incorrect NextFireTime when 'schedule-trigger-relative-to-replaced-trigger' = 'true'")]),e._v(" "),o("li",[e._v("Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' from assembly mscorlib")]),e._v(" "),o("li",[e._v("TriggerBuilder.UsingJobData(JobDataMap newJobDataMap) should ovewrite existing data")])]),e._v(" "),o("Download")],1)}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/29.d3bbf14c.js b/assets/js/29.d3bbf14c.js new file mode 100644 index 000000000..55500dbd4 --- /dev/null +++ b/assets/js/29.d3bbf14c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{403:function(e,r,n){"use strict";n.r(r);var l=n(26),t=Object(l.a)({},(function(){var e=this,r=e.$createElement,n=e._self._c||r;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("p",[e._v("This is a minor release containing mostly bug fixes.")]),e._v(" "),n("p",[n("strong",[e._v("NEW FEATURE")])]),e._v(" "),n("ul",[n("li",[e._v("Add mysql 6.9.5 provider support")])]),e._v(" "),n("p",[n("strong",[e._v("FIXES")])]),e._v(" "),n("ul",[n("li",[e._v("Avoid unnecessary object allocations in CronExpression")]),e._v(" "),n("li",[e._v("CalendarIntervalTrigger and DailyTimeIntervalTrigger produce incorrect schedule builders")]),e._v(" "),n("li",[e._v("Incorrect multiplication factor in DailyTimeIntervalScheduleBuilder.EndingDailyAfterCount()")]),e._v(" "),n("li",[e._v("AnnualCalendar SetDayExcluded does not update internal data structures if base calendar excludes date")]),e._v(" "),n("li",[e._v("Ensure IDriverDelegate members in StdAdoDelegate are virtual")]),e._v(" "),n("li",[e._v("Several XML documentation spelling error fixes")])]),e._v(" "),n("Download")],1)}),[],!1,null,null,null);r.default=t.exports}}]); \ No newline at end of file diff --git a/assets/js/3.836353be.js b/assets/js/3.836353be.js new file mode 100644 index 000000000..c055b529a --- /dev/null +++ b/assets/js/3.836353be.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{319:function(t,e,n){"use strict";n.d(e,"d",(function(){return r})),n.d(e,"a",(function(){return a})),n.d(e,"i",(function(){return s})),n.d(e,"f",(function(){return u})),n.d(e,"g",(function(){return l})),n.d(e,"h",(function(){return c})),n.d(e,"b",(function(){return h})),n.d(e,"e",(function(){return f})),n.d(e,"k",(function(){return p})),n.d(e,"l",(function(){return d})),n.d(e,"c",(function(){return v})),n.d(e,"j",(function(){return m}));n(50),n(70),n(320),n(321),n(179),n(49),n(72),n(73),n(27),n(101),n(170);var r=/#.*$/,i=/\.(md|html)$/,a=/\/$/,s=/^[a-z]+:/i;function o(t){return decodeURI(t).replace(r,"").replace(i,"")}function u(t){return s.test(t)}function l(t){return/^mailto:/.test(t)}function c(t){return/^tel:/.test(t)}function h(t){if(u(t))return t;var e=t.match(r),n=e?e[0]:"",i=o(t);return a.test(i)?t:i+".html"+n}function f(t,e){var n=decodeURIComponent(t.hash),i=function(t){var e=t.match(r);if(e)return e[0]}(e);return(!i||n===i)&&o(t.path)===o(e)}function p(t,e,n){if(u(e))return{type:"external",path:e};n&&(e=function(t,e,n){var r=t.charAt(0);if("/"===r)return t;if("?"===r||"#"===r)return e+t;var i=e.split("/");n&&i[i.length-1]||i.pop();for(var a=t.replace(/^\//,"").split("/"),s=0;s3&&void 0!==arguments[3]?arguments[3]:1;if("string"==typeof e)return p(n,e,r);if(Array.isArray(e))return Object.assign(p(n,e[0],r),{title:e[1]});var a=e.children||[];return 0===a.length&&e.path?Object.assign(p(n,e.path,r),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:a.map((function(e){return t(e,n,r,i+1)})),collapsable:!1!==e.collapsable}}(t,i,l)})):[]}return[]}function g(t){var e=v(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map((function(e){return{type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}}))}]}function v(t){var e;return(t=t.map((function(t){return Object.assign({},t)}))).forEach((function(t){2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)})),t.filter((function(t){return 2===t.level}))}function m(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},320:function(t,e,n){"use strict";var r=n(176),i=n(5),a=n(14),s=n(21),o=n(177),u=n(178);r("match",1,(function(t,e,n){return[function(e){var n=s(this),r=null==e?void 0:e[t];return void 0!==r?r.call(e,n):new RegExp(e)[t](String(n))},function(t){var r=n(e,t,this);if(r.done)return r.value;var s=i(t),l=String(this);if(!s.global)return u(s,l);var c=s.unicode;s.lastIndex=0;for(var h,f=[],p=0;null!==(h=u(s,l));){var d=String(h[0]);f[p]=d,""===d&&(s.lastIndex=o(l,a(s.lastIndex),c)),p++}return 0===p?null:f}]}))},321:function(t,e,n){"use strict";var r=n(176),i=n(173),a=n(5),s=n(21),o=n(105),u=n(177),l=n(14),c=n(178),h=n(109),f=n(175).UNSUPPORTED_Y,p=[].push,d=Math.min;r("split",2,(function(t,e,n){var r;return r="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var r=String(s(this)),a=void 0===n?4294967295:n>>>0;if(0===a)return[];if(void 0===t)return[r];if(!i(t))return e.call(r,t,a);for(var o,u,l,c=[],f=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),d=0,g=new RegExp(t.source,f+"g");(o=h.call(g,r))&&!((u=g.lastIndex)>d&&(c.push(r.slice(d,o.index)),o.length>1&&o.index=a));)g.lastIndex===o.index&&g.lastIndex++;return d===r.length?!l&&g.test("")||c.push(""):c.push(r.slice(d)),c.length>a?c.slice(0,a):c}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:e.call(this,t,n)}:e,[function(e,n){var i=s(this),a=null==e?void 0:e[t];return void 0!==a?a.call(e,i,n):r.call(String(i),e,n)},function(t,i){var s=n(r,t,this,i,r!==e);if(s.done)return s.value;var h=a(t),p=String(this),g=o(h,RegExp),v=h.unicode,m=(h.ignoreCase?"i":"")+(h.multiline?"m":"")+(h.unicode?"u":"")+(f?"g":"y"),b=new g(f?"^(?:"+h.source+")":h,m),k=void 0===i?4294967295:i>>>0;if(0===k)return[];if(0===p.length)return null===c(b,p)?[p]:[];for(var y=0,_=0,x=[];_-1)&&(e=e.replace(/y/g,""));var o=s(_?new m(t,e):m(t,e),r?this:b,L);return x&&n&&d(o,{sticky:n}),o},w=function(t){t in L||o(L,t,{configurable:!0,get:function(){return m[t]},set:function(e){m[t]=e}})},C=u(m),S=0;C.length>S;)w(C[S++]);b.constructor=L,L.prototype=b,f(i,"RegExp",L)}g("RegExp")},327:function(t,e,n){"use strict";var r=n(11),i=n(5),a=n(1),s=n(174),o=RegExp.prototype,u=o.toString,l=a((function(){return"/a/b"!=u.call({source:"a",flags:"b"})})),c="toString"!=u.name;(l||c)&&r(RegExp.prototype,"toString",(function(){var t=i(this),e=String(t.source),n=t.flags;return"/"+e+"/"+String(void 0===n&&t instanceof RegExp&&!("flags"in o)?s.call(t):n)}),{unsafe:!0})},328:function(t,e,n){},329:function(t,e,n){},330:function(t,e,n){},331:function(t,e,n){},332:function(t,e,n){},333:function(t,e,n){},334:function(t,e){t.exports=function(t){return null==t}},335:function(t,e,n){},336:function(t,e,n){},337:function(t,e,n){},338:function(t,e,n){},339:function(t,e,n){},340:function(t,e,n){},344:function(t,e,n){"use strict";n.r(e);n(99);var r=n(319),i={name:"SidebarGroup",components:{DropdownTransition:n(345).a},props:["item","open","collapsable","depth"],beforeCreate:function(){this.$options.components.SidebarLinks=n(344).default},methods:{isActive:r.e}},a=(n(371),n(26)),s=Object(a.a)(i,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?n("RouterLink",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),n("DropdownTransition",[t.open||!t.collapsable?n("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,"initial-open-group-index":t.item.initialOpenGroupIndex,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(372),n(49);function o(t,e,n,r,i){var a={props:{to:e,activeClass:"",exactActiveClass:""},class:{active:r,"sidebar-link":!0}};return i>2&&(a.style={"padding-left":i+"rem"}),t("RouterLink",a,n)}function u(t,e,n,i,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1;return!e||s>a?null:t("ul",{class:"sidebar-sub-headers"},e.map((function(e){var l=Object(r.e)(i,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[o(t,n+"#"+e.slug,e.title,l,e.level-1),u(t,e.children,n,i,a,s+1)])})))}var l={functional:!0,props:["item","sidebarDepth"],render:function(t,e){var n=e.parent,i=n.$page,a=(n.$site,n.$route),s=n.$themeConfig,l=n.$themeLocaleConfig,c=e.props,h=c.item,f=c.sidebarDepth,p=Object(r.e)(a,h.path),d="auto"===h.type?p||h.children.some((function(t){return Object(r.e)(a,h.basePath+"#"+t.slug)})):p,g="external"===h.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,h.path,h.title||h.path):o(t,h.path,h.title||h.path,d),v=[i.frontmatter.sidebarDepth,f,l.sidebarDepth,s.sidebarDepth,1].find((function(t){return void 0!==t})),m=l.displayAllHeaders||s.displayAllHeaders;return"auto"===h.type?[g,u(t,h.children,h.basePath,a,v)]:(d||m)&&h.headers&&!r.d.test(h.path)?[g,u(t,Object(r.c)(h.headers),h.path,a,v)]:g}};n(373);function c(t,e){if("group"===e.type){var n=e.path&&Object(r.e)(t,e.path),i=e.children.some((function(e){return"group"===e.type?c(t,e):"page"===e.type&&Object(r.e)(t,e.path)}));return n||i}return!1}var h={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(a.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data:function(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route:function(){this.refreshIndex()}},created:function(){this.refreshIndex()},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return Object(r.e)(this.$route,t.regularPath)}}},f=Object(a.a)(h,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(e,r){return n("li",{key:r},["group"===e.type?n("SidebarGroup",{attrs:{item:e,open:r===t.openGroupIndex,collapsable:e.collapsable||e.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(r)}}}):n("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:e}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=f.exports},345:function(t,e,n){"use strict";var r={name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}},i=(n(363),n(26)),a=Object(i.a)(r,(function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=a.exports},346:function(t,e,n){"use strict";var r=n(0),i=n(347);r({target:"String",proto:!0,forced:n(348)("link")},{link:function(t){return i(this,"a","href",t)}})},347:function(t,e,n){var r=n(21),i=/"/g;t.exports=function(t,e,n,a){var s=String(r(t)),o="<"+e;return""!==n&&(o+=" "+n+'="'+String(a).replace(i,""")+'"'),o+">"+s+""}},348:function(t,e,n){var r=n(1);t.exports=function(t){return r((function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}))}},349:function(t,e,n){"use strict";n(322)},350:function(t,e,n){var r=n(0),i=n(351);r({global:!0,forced:parseInt!=i},{parseInt:i})},351:function(t,e,n){var r=n(3),i=n(182).trim,a=n(183),s=r.parseInt,o=/^[+-]?0[Xx]/,u=8!==s(a+"08")||22!==s(a+"0x16");t.exports=u?function(t,e){var n=i(String(t));return s(n,e>>>0||(o.test(n)?16:10))}:s},352:function(t,e,n){var r=n(0),i=n(1),a=n(15),s=n(23).f,o=n(6),u=i((function(){s(1)}));r({target:"Object",stat:!0,forced:!o||u,sham:!o},{getOwnPropertyDescriptor:function(t,e){return s(a(t),e)}})},353:function(t,e,n){var r=n(0),i=n(6);r({target:"Object",stat:!0,forced:!i,sham:!i},{defineProperties:n(171)})},354:function(t,e,n){"use strict";n(12);var r,i=n(0),a=n(6),s=n(323),o=n(3),u=n(171),l=n(11),c=n(172),h=n(7),f=n(187),p=n(189),d=n(106).codeAt,g=n(355),v=n(51),m=n(356),b=n(32),k=o.URL,y=m.URLSearchParams,_=m.getState,x=b.set,L=b.getterFor("URL"),w=Math.floor,C=Math.pow,S=/[A-Za-z]/,$=/[\d+-.A-Za-z]/,O=/\d/,R=/^(0x|0X)/,I=/^[0-7]+$/,j=/^\d+$/,U=/^[\dA-Fa-f]+$/,P=/[\u0000\t\u000A\u000D #%/:?@[\\]]/,A=/[\u0000\t\u000A\u000D #/:?@[\\]]/,E=/^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g,T=/[\t\u000A\u000D]/g,N=function(t,e){var n,r,i;if("["==e.charAt(0)){if("]"!=e.charAt(e.length-1))return"Invalid host";if(!(n=D(e.slice(1,-1))))return"Invalid host";t.host=n}else if(X(t)){if(e=g(e),P.test(e))return"Invalid host";if(null===(n=B(e)))return"Invalid host";t.host=n}else{if(A.test(e))return"Invalid host";for(n="",r=p(e),i=0;i4)return t;for(n=[],r=0;r1&&"0"==i.charAt(0)&&(a=R.test(i)?16:8,i=i.slice(8==a?1:2)),""===i)s=0;else{if(!(10==a?j:8==a?I:U).test(i))return t;s=parseInt(i,a)}n.push(s)}for(r=0;r=C(256,5-e))return null}else if(s>255)return null;for(o=n.pop(),r=0;r6)return;for(r=0;f();){if(i=null,r>0){if(!("."==f()&&r<4))return;h++}if(!O.test(f()))return;for(;O.test(f());){if(a=parseInt(f(),10),null===i)i=a;else{if(0==i)return;i=10*i+a}if(i>255)return;h++}u[l]=256*u[l]+i,2!=++r&&4!=r||l++}if(4!=r)return;break}if(":"==f()){if(h++,!f())return}else if(f())return;u[l++]=e}else{if(null!==c)return;h++,c=++l}}if(null!==c)for(s=l-c,l=7;0!=l&&s>0;)o=u[l],u[l--]=u[c+s-1],u[c+--s]=o;else if(8!=l)return;return u},q=function(t){var e,n,r,i;if("number"==typeof t){for(e=[],n=0;n<4;n++)e.unshift(t%256),t=w(t/256);return e.join(".")}if("object"==typeof t){for(e="",r=function(t){for(var e=null,n=1,r=null,i=0,a=0;a<8;a++)0!==t[a]?(i>n&&(e=r,n=i),r=null,i=0):(null===r&&(r=a),++i);return i>n&&(e=r,n=i),e}(t),n=0;n<8;n++)i&&0===t[n]||(i&&(i=!1),r===n?(e+=n?":":"::",i=!0):(e+=t[n].toString(16),n<7&&(e+=":")));return"["+e+"]"}return t},H={},W=f({},H,{" ":1,'"':1,"<":1,">":1,"`":1}),G=f({},W,{"#":1,"?":1,"{":1,"}":1}),M=f({},G,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),F=function(t,e){var n=d(t,0);return n>32&&n<127&&!h(e,t)?t:encodeURIComponent(t)},z={ftp:21,file:null,http:80,https:443,ws:80,wss:443},X=function(t){return h(z,t.scheme)},V=function(t){return""!=t.username||""!=t.password},J=function(t){return!t.host||t.cannotBeABaseURL||"file"==t.scheme},Y=function(t,e){var n;return 2==t.length&&S.test(t.charAt(0))&&(":"==(n=t.charAt(1))||!e&&"|"==n)},Z=function(t){var e;return t.length>1&&Y(t.slice(0,2))&&(2==t.length||"/"===(e=t.charAt(2))||"\\"===e||"?"===e||"#"===e)},K=function(t){var e=t.path,n=e.length;!n||"file"==t.scheme&&1==n&&Y(e[0],!0)||e.pop()},Q=function(t){return"."===t||"%2e"===t.toLowerCase()},tt={},et={},nt={},rt={},it={},at={},st={},ot={},ut={},lt={},ct={},ht={},ft={},pt={},dt={},gt={},vt={},mt={},bt={},kt={},yt={},_t=function(t,e,n,i){var a,s,o,u,l,c=n||tt,f=0,d="",g=!1,v=!1,m=!1;for(n||(t.scheme="",t.username="",t.password="",t.host=null,t.port=null,t.path=[],t.query=null,t.fragment=null,t.cannotBeABaseURL=!1,e=e.replace(E,"")),e=e.replace(T,""),a=p(e);f<=a.length;){switch(s=a[f],c){case tt:if(!s||!S.test(s)){if(n)return"Invalid scheme";c=nt;continue}d+=s.toLowerCase(),c=et;break;case et:if(s&&($.test(s)||"+"==s||"-"==s||"."==s))d+=s.toLowerCase();else{if(":"!=s){if(n)return"Invalid scheme";d="",c=nt,f=0;continue}if(n&&(X(t)!=h(z,d)||"file"==d&&(V(t)||null!==t.port)||"file"==t.scheme&&!t.host))return;if(t.scheme=d,n)return void(X(t)&&z[t.scheme]==t.port&&(t.port=null));d="","file"==t.scheme?c=pt:X(t)&&i&&i.scheme==t.scheme?c=rt:X(t)?c=ot:"/"==a[f+1]?(c=it,f++):(t.cannotBeABaseURL=!0,t.path.push(""),c=bt)}break;case nt:if(!i||i.cannotBeABaseURL&&"#"!=s)return"Invalid scheme";if(i.cannotBeABaseURL&&"#"==s){t.scheme=i.scheme,t.path=i.path.slice(),t.query=i.query,t.fragment="",t.cannotBeABaseURL=!0,c=yt;break}c="file"==i.scheme?pt:at;continue;case rt:if("/"!=s||"/"!=a[f+1]){c=at;continue}c=ut,f++;break;case it:if("/"==s){c=lt;break}c=mt;continue;case at:if(t.scheme=i.scheme,s==r)t.username=i.username,t.password=i.password,t.host=i.host,t.port=i.port,t.path=i.path.slice(),t.query=i.query;else if("/"==s||"\\"==s&&X(t))c=st;else if("?"==s)t.username=i.username,t.password=i.password,t.host=i.host,t.port=i.port,t.path=i.path.slice(),t.query="",c=kt;else{if("#"!=s){t.username=i.username,t.password=i.password,t.host=i.host,t.port=i.port,t.path=i.path.slice(),t.path.pop(),c=mt;continue}t.username=i.username,t.password=i.password,t.host=i.host,t.port=i.port,t.path=i.path.slice(),t.query=i.query,t.fragment="",c=yt}break;case st:if(!X(t)||"/"!=s&&"\\"!=s){if("/"!=s){t.username=i.username,t.password=i.password,t.host=i.host,t.port=i.port,c=mt;continue}c=lt}else c=ut;break;case ot:if(c=ut,"/"!=s||"/"!=d.charAt(f+1))continue;f++;break;case ut:if("/"!=s&&"\\"!=s){c=lt;continue}break;case lt:if("@"==s){g&&(d="%40"+d),g=!0,o=p(d);for(var b=0;b65535)return"Invalid port";t.port=X(t)&&_===z[t.scheme]?null:_,d=""}if(n)return;c=vt;continue}return"Invalid port"}d+=s;break;case pt:if(t.scheme="file","/"==s||"\\"==s)c=dt;else{if(!i||"file"!=i.scheme){c=mt;continue}if(s==r)t.host=i.host,t.path=i.path.slice(),t.query=i.query;else if("?"==s)t.host=i.host,t.path=i.path.slice(),t.query="",c=kt;else{if("#"!=s){Z(a.slice(f).join(""))||(t.host=i.host,t.path=i.path.slice(),K(t)),c=mt;continue}t.host=i.host,t.path=i.path.slice(),t.query=i.query,t.fragment="",c=yt}}break;case dt:if("/"==s||"\\"==s){c=gt;break}i&&"file"==i.scheme&&!Z(a.slice(f).join(""))&&(Y(i.path[0],!0)?t.path.push(i.path[0]):t.host=i.host),c=mt;continue;case gt:if(s==r||"/"==s||"\\"==s||"?"==s||"#"==s){if(!n&&Y(d))c=mt;else if(""==d){if(t.host="",n)return;c=vt}else{if(u=N(t,d))return u;if("localhost"==t.host&&(t.host=""),n)return;d="",c=vt}continue}d+=s;break;case vt:if(X(t)){if(c=mt,"/"!=s&&"\\"!=s)continue}else if(n||"?"!=s)if(n||"#"!=s){if(s!=r&&(c=mt,"/"!=s))continue}else t.fragment="",c=yt;else t.query="",c=kt;break;case mt:if(s==r||"/"==s||"\\"==s&&X(t)||!n&&("?"==s||"#"==s)){if(".."===(l=(l=d).toLowerCase())||"%2e."===l||".%2e"===l||"%2e%2e"===l?(K(t),"/"==s||"\\"==s&&X(t)||t.path.push("")):Q(d)?"/"==s||"\\"==s&&X(t)||t.path.push(""):("file"==t.scheme&&!t.path.length&&Y(d)&&(t.host&&(t.host=""),d=d.charAt(0)+":"),t.path.push(d)),d="","file"==t.scheme&&(s==r||"?"==s||"#"==s))for(;t.path.length>1&&""===t.path[0];)t.path.shift();"?"==s?(t.query="",c=kt):"#"==s&&(t.fragment="",c=yt)}else d+=F(s,G);break;case bt:"?"==s?(t.query="",c=kt):"#"==s?(t.fragment="",c=yt):s!=r&&(t.path[0]+=F(s,H));break;case kt:n||"#"!=s?s!=r&&("'"==s&&X(t)?t.query+="%27":t.query+="#"==s?"%23":F(s,H)):(t.fragment="",c=yt);break;case yt:s!=r&&(t.fragment+=F(s,W))}f++}},xt=function(t){var e,n,r=c(this,xt,"URL"),i=arguments.length>1?arguments[1]:void 0,s=String(t),o=x(r,{type:"URL"});if(void 0!==i)if(i instanceof xt)e=L(i);else if(n=_t(e={},String(i)))throw TypeError(n);if(n=_t(o,s,null,e))throw TypeError(n);var u=o.searchParams=new y,l=_(u);l.updateSearchParams(o.query),l.updateURL=function(){o.query=String(u)||null},a||(r.href=wt.call(r),r.origin=Ct.call(r),r.protocol=St.call(r),r.username=$t.call(r),r.password=Ot.call(r),r.host=Rt.call(r),r.hostname=It.call(r),r.port=jt.call(r),r.pathname=Ut.call(r),r.search=Pt.call(r),r.searchParams=At.call(r),r.hash=Et.call(r))},Lt=xt.prototype,wt=function(){var t=L(this),e=t.scheme,n=t.username,r=t.password,i=t.host,a=t.port,s=t.path,o=t.query,u=t.fragment,l=e+":";return null!==i?(l+="//",V(t)&&(l+=n+(r?":"+r:"")+"@"),l+=q(i),null!==a&&(l+=":"+a)):"file"==e&&(l+="//"),l+=t.cannotBeABaseURL?s[0]:s.length?"/"+s.join("/"):"",null!==o&&(l+="?"+o),null!==u&&(l+="#"+u),l},Ct=function(){var t=L(this),e=t.scheme,n=t.port;if("blob"==e)try{return new URL(e.path[0]).origin}catch(t){return"null"}return"file"!=e&&X(t)?e+"://"+q(t.host)+(null!==n?":"+n:""):"null"},St=function(){return L(this).scheme+":"},$t=function(){return L(this).username},Ot=function(){return L(this).password},Rt=function(){var t=L(this),e=t.host,n=t.port;return null===e?"":null===n?q(e):q(e)+":"+n},It=function(){var t=L(this).host;return null===t?"":q(t)},jt=function(){var t=L(this).port;return null===t?"":String(t)},Ut=function(){var t=L(this),e=t.path;return t.cannotBeABaseURL?e[0]:e.length?"/"+e.join("/"):""},Pt=function(){var t=L(this).query;return t?"?"+t:""},At=function(){return L(this).searchParams},Et=function(){var t=L(this).fragment;return t?"#"+t:""},Tt=function(t,e){return{get:t,set:e,configurable:!0,enumerable:!0}};if(a&&u(Lt,{href:Tt(wt,(function(t){var e=L(this),n=String(t),r=_t(e,n);if(r)throw TypeError(r);_(e.searchParams).updateSearchParams(e.query)})),origin:Tt(Ct),protocol:Tt(St,(function(t){var e=L(this);_t(e,String(t)+":",tt)})),username:Tt($t,(function(t){var e=L(this),n=p(String(t));if(!J(e)){e.username="";for(var r=0;r>1,t+=s(t/e);t>455;r+=36)t=s(t/35);return s(r+36*t/(t+38))},c=function(t){var e,n,r=[],i=(t=function(t){for(var e=[],n=0,r=t.length;n=55296&&i<=56319&&n=c&&ns((2147483647-h)/v))throw RangeError(a);for(h+=(g-c)*v,c=g,e=0;e2147483647)throw RangeError(a);if(n==c){for(var m=h,b=36;;b+=36){var k=b<=f?1:b>=f+26?26:b-f;if(m0?arguments[0]:void 0,c=this,p=[];if(C(c,{type:"URLSearchParams",entries:p,updateURL:function(){},updateSearchParams:B}),void 0!==l)if(v(l))if("function"==typeof(t=y(l)))for(n=(e=t.call(l)).next;!(r=n.call(e)).done;){if((s=(a=(i=k(g(r.value))).next).call(i)).done||(o=a.call(i)).done||!a.call(i).done)throw TypeError("Expected sequence with length 2");p.push({key:s.value+"",value:o.value+""})}else for(u in l)f(l,u)&&p.push({key:u,value:l[u]+""});else N(p,"string"==typeof l?"?"===l.charAt(0)?l.slice(1):l:l+"")},W=H.prototype;o(W,{append:function(t,e){D(arguments.length,2);var n=S(this);n.entries.push({key:t+"",value:e+""}),n.updateURL()},delete:function(t){D(arguments.length,1);for(var e=S(this),n=e.entries,r=t+"",i=0;it.key){i.splice(e,0,t);break}e===n&&i.push(t)}r.updateURL()},forEach:function(t){for(var e,n=S(this).entries,r=p(t,arguments.length>1?arguments[1]:void 0,3),i=0;i1&&(v(e=arguments[1])&&(n=e.body,"URLSearchParams"===d(n)&&((r=e.headers?new L(e.headers):new L).has("content-type")||r.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"),e=m(e,{body:b(0,String(n)),headers:b(0,r)}))),i.push(e)),x.apply(this,i)}}),t.exports={URLSearchParams:H,getState:S}},357:function(t,e,n){var r=n(5),i=n(100);t.exports=function(t){var e=i(t);if("function"!=typeof e)throw TypeError(String(t)+" is not iterable");return r(e.call(t))}},358:function(t,e,n){"use strict";n(324)},359:function(t,e,n){var r=n(1),i=n(183);t.exports=function(t){return r((function(){return!!i[t]()||"​…᠎"!="​…᠎"[t]()||i[t].name!==t}))}},360:function(t,e,n){"use strict";var r,i=n(0),a=n(23).f,s=n(14),o=n(107),u=n(21),l=n(108),c=n(22),h="".endsWith,f=Math.min,p=l("endsWith");i({target:"String",proto:!0,forced:!!(c||p||(r=a(String.prototype,"endsWith"),!r||r.writable))&&!p},{endsWith:function(t){var e=String(u(this));o(t);var n=arguments.length>1?arguments[1]:void 0,r=s(e.length),i=void 0===n?r:f(s(n),r),a=String(t);return h?h.call(e,a,i):e.slice(i-a.length,i)===a}})},361:function(t,e,n){"use strict";n(328)},362:function(t,e,n){"use strict";n(329)},363:function(t,e,n){"use strict";n(330)},364:function(t,e,n){"use strict";n(331)},365:function(t,e,n){"use strict";n(332)},366:function(t,e,n){"use strict";n(333)},367:function(t,e,n){"use strict";n(335)},368:function(t,e,n){var r=n(36),i=n(17),a=n(30);t.exports=function(t){return"string"==typeof t||!i(t)&&a(t)&&"[object String]"==r(t)}},369:function(t,e,n){"use strict";n(336)},370:function(t,e,n){"use strict";n(337)},371:function(t,e,n){"use strict";n(338)},372:function(t,e,n){"use strict";var r=n(0),i=n(34).find,a=n(103),s=!0;"find"in[]&&Array(1).find((function(){s=!1})),r({target:"Array",proto:!0,forced:s},{find:function(t){return i(this,t,arguments.length>1?arguments[1]:void 0)}}),a("find")},373:function(t,e,n){"use strict";n(339)},374:function(t,e,n){"use strict";n(340)},381:function(t,e,n){"use strict";n.r(e);n(346),n(99),n(71);var r=n(319),i={name:"NavLink",props:{item:{required:!0}},computed:{link:function(){return Object(r.b)(this.item.link)},exact:function(){var t=this;return this.$site.locales?Object.keys(this.$site.locales).some((function(e){return e===t.link})):"/"===this.link},isNonHttpURI:function(){return Object(r.g)(this.link)||Object(r.h)(this.link)},isBlankTarget:function(){return"_blank"===this.target},isInternal:function(){return!Object(r.f)(this.link)&&!this.isBlankTarget},target:function(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(r.f)(this.link)?"_blank":""},rel:function(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction:function(){this.$emit("focusout")}}},a=n(26),s=Object(a.a)(i,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.isInternal?n("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction(e)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):n("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?n("OutboundLink"):t._e()],1)}),[],!1,null,null,null).exports,o={name:"Home",components:{NavLink:s},computed:{data:function(){return this.$page.frontmatter},actionLink:function(){return{link:this.data.actionLink,text:this.data.actionText}}}},u=(n(349),Object(a.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("main",{staticClass:"home",attrs:{"aria-labelledby":null!==t.data.heroText?"main-title":null}},[n("header",{staticClass:"hero"},[t.data.heroImage?n("img",{attrs:{src:t.$withBase(t.data.heroImage),alt:t.data.heroAlt||"hero"}}):t._e(),t._v(" "),null!==t.data.heroText?n("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.data.heroText||t.$title||"Hello")+"\n ")]):t._e(),t._v(" "),null!==t.data.tagline?n("p",{staticClass:"description"},[t._v("\n "+t._s(t.data.tagline||t.$description||"Welcome to your VuePress site")+"\n ")]):t._e(),t._v(" "),t.data.actionText&&t.data.actionLink?n("p",{staticClass:"action"},[n("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.data.features&&t.data.features.length?n("div",{staticClass:"features"},t._l(t.data.features,(function(e,r){return n("div",{key:r,staticClass:"feature"},[n("h2",[t._v(t._s(e.title))]),t._v(" "),n("p",[t._v(t._s(e.details))])])})),0):t._e(),t._v(" "),n("Content",{staticClass:"theme-default-content custom"}),t._v(" "),t.data.footer?n("div",{staticClass:"footer"},[t._v("\n "+t._s(t.data.footer)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports),l=(n(350),n(35),n(27),n(352),n(72),n(73),n(188),n(353),n(110),n(98));function c(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function h(t){for(var e=1;e',this.initialize(t,e)}}}),d=(n(358),Object(a.a)(p,(function(){var t=this.$createElement,e=this._self._c||t;return e("form",{staticClass:"algolia-search-wrapper search-box",attrs:{id:"search-form",role:"search"}},[e("input",{staticClass:"search-query",attrs:{id:"algolia-search-input",placeholder:this.placeholder}})])}),[],!1,null,null,null).exports),g=(n(325),n(170),n(101),n(320),n(190),n(191),n(179),n(326),n(327),n(49),n(321),n(360),n(192)),v=n.n(g),m=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=v()(e,"title","");return v()(e,"frontmatter.tags")&&(r+=" ".concat(e.frontmatter.tags.join(" "))),n&&(r+=" ".concat(n)),b(t,r)},b=function(t,e){var n=function(t){return t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")},r=new RegExp("[^\0-]"),i=t.split(/\s+/g).map((function(t){return t.trim()})).filter((function(t){return!!t}));if(r.test(t))return i.some((function(t){return e.toLowerCase().indexOf(t)>-1}));var a=t.endsWith(" ");return new RegExp(i.map((function(t,e){return i.length!==e+1||a?"(?=.*\\b".concat(n(t),"\\b)"):"(?=.*\\b".concat(n(t),")")})).join("")+".+","gi").test(e)},k={name:"SearchBox",data:function(){return{query:"",focused:!1,focusIndex:0,placeholder:void 0}},computed:{showSuggestions:function(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions:function(){var t=this.query.trim().toLowerCase();if(t){for(var e=this.$site.pages,n=this.$site.themeConfig.searchMaxSuggestions||5,r=this.$localePath,i=[],a=0;a=n);a++){var s=e[a];if(this.getPageLocalePath(s)===r&&this.isSearchable(s))if(m(t,s))i.push(s);else if(s.headers)for(var o=0;o=n);o++){var u=s.headers[o];u.title&&m(t,s,u.title)&&i.push(Object.assign({},s,{path:s.path+"#"+u.slug,header:u}))}}return i}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted:function(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy:function(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable:function(t){var e=null;return null===e||(e=Array.isArray(e)?e:new Array(e)).filter((function(e){return t.path.match(e)})).length>0},onHotkey:function(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),_=(n(362),Object(a.a)({},(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[n("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[n("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),x=n(46),L=n(345),w=n(193),C=n.n(w),S={name:"DropdownLink",components:{NavLink:s,DropdownTransition:L.a},props:{item:{required:!0}},data:function(){return{open:!1}},computed:{dropdownAriaLabel:function(){return this.item.ariaLabel||this.item.text}},watch:{$route:function(){this.open=!1}},methods:{setOpen:function(t){this.open=t},isLastItemOfArray:function(t,e){return C()(e)===t},handleDropdown:function(){0===event.detail&&this.setOpen(!this.open)}}},$=(n(364),{name:"NavLinks",components:{NavLink:s,DropdownLink:Object(a.a)(S,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow down"})]),t._v(" "),n("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(e,r){return n("li",{key:e.link||r,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v("\n "+t._s(e.text)+"\n ")]):t._e(),t._v(" "),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,(function(r){return n("li",{key:r.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:r},on:{focusout:function(n){t.isLastItemOfArray(r,e.items)&&t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0):n("NavLink",{attrs:{item:e},on:{focusout:function(n){t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,r=this.$router.options.routes,i=this.$site.themeConfig.locales||{},a={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(e).map((function(a){var s,o=e[a],u=i[a]&&i[a].label||o.lang;return o.lang===t.$lang?s=n:(s=n.replace(t.$localeConfig.path,a),r.some((function(t){return t.path===s}))||(s=a)),{text:u,link:s}}))};return[].concat(Object(x.a)(this.userNav),[a])}return this.userNav},userLinks:function(){return(this.nav||[]).map((function(t){return Object.assign(Object(r.j)(t),{items:(t.items||[]).map(r.j)})}))},repoLink:function(){var t=this.$site.themeConfig.repo;return t?/^https?:/.test(t)?t:"https://github.com/".concat(t):null},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;nMath.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),X=Object(a.a)(z,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),n("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("page-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("page-bottom")]},proxy:!0}],null,!0)})],1)}),[],!1,null,null,null);e.default=X.exports}}]); \ No newline at end of file diff --git a/assets/js/30.2285aa3b.js b/assets/js/30.2285aa3b.js new file mode 100644 index 000000000..350109b46 --- /dev/null +++ b/assets/js/30.2285aa3b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{404:function(e,t,o){"use strict";o.r(t);var i=o(26),r=Object(i.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("This is a minor release containing mostly bug fixes.")]),e._v(" "),o("p",[o("strong",[e._v("NEW FEATURE")])]),e._v(" "),o("ul",[o("li",[e._v("Support generic job types with AdoJobStore")])]),e._v(" "),o("p",[o("strong",[e._v("FIXES")])]),e._v(" "),o("ul",[o("li",[e._v("AdoJobStore doesn't notify about removing orphaned job")]),e._v(" "),o("li",[e._v("Store null JobData in JobDetails if it's empty")]),e._v(" "),o("li",[e._v("Documentation error in SimpleTriggerImpl UpdateAfterMisfire")]),e._v(" "),o("li",[e._v("Ensure IDriverDelegate members in StdAdoDelegate are virtual")])]),e._v(" "),o("Download")],1)}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/31.de5c4db1.js b/assets/js/31.de5c4db1.js new file mode 100644 index 000000000..fafe3dba5 --- /dev/null +++ b/assets/js/31.de5c4db1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{405:function(e,t,a){"use strict";a.r(t);var o=a(26),n=Object(o.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("p",[e._v("This is the first alpha release from the long-awaited v3 branch. This is a big overhaul (and still in progress). Internals are being modernized whilst still trying to keep sane upgrade path.")]),e._v(" "),a("p",[e._v("A big thank you goes to "),a("a",{attrs:{href:"https://github.com/mjrousos",target:"_blank",rel:"noopener noreferrer"}},[e._v("Mike Rousos"),a("OutboundLink")],1),e._v(" who really made it possible to get Quartz.NET working on .NET Core. "),a("a",{attrs:{href:"https://github.com/danielmarbach",target:"_blank",rel:"noopener noreferrer"}},[e._v("Daniel Marbach"),a("OutboundLink")],1),e._v(" also contributed a lot with ideas and code to async side. And of course never forgetting the community members that have provided feedback and fixes.")]),e._v(" "),a("p",[e._v("Please see the "),a("RouterLink",{attrs:{to:"/documentation/quartz-3.x/migration-guide.html"}},[e._v("migration guide")]),e._v(" that is a work in progess.")],1),e._v(" "),a("p",[a("strong",[e._v("Use at your own risk, might not be that production ready yet")])]),e._v(" "),a("p",[e._v("What does alpha mean?")]),e._v(" "),a("ul",[a("li",[e._v("All existing (and new) tests passing")]),e._v(" "),a("li",[e._v("Cheese might still get moved, alpha means that APIs can change, features can come and go")])]),e._v(" "),a("p",[a("strong",[e._v("NEW FEATURE")])]),e._v(" "),a("ul",[a("li",[e._v("Task based jobs with async/await support, internals work in async/await manner")]),e._v(" "),a("li",[e._v("Support .NET Core / netstandard 1.3")]),e._v(" "),a("li",[e._v("Separate NuGet package Quartz.Serialization.Json to enable JSON based AdoJobStore serialization (no binary serialization available in .NET Core)")]),e._v(" "),a("li",[e._v("Common.Logging removed from dependencies")]),e._v(" "),a("li",[e._v("C5 Collections removed from ILMerge process, no longer needed")])]),e._v(" "),a("p",[a("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),a("ul",[a("li",[e._v(".NET 4.5/netstandard1.3 required")]),e._v(" "),a("li",[e._v("SimpleThreadPool is gone, old owned threads are gone")]),e._v(" "),a("li",[e._v("Scheduler methods have been changed to be Task based, remember to await them")]),e._v(" "),a("li",[e._v("IJob interface now returns a task")]),e._v(" "),a("li",[e._v("Some IList properties have been changed to IReadOnlyList to properly reflect intent")]),e._v(" "),a("li",[e._v("SQL Server CE support has been dropped")]),e._v(" "),a("li",[e._v("DailyCalendar uses now datetimes for excluded dates and has ISet interface to access them")]),e._v(" "),a("li",[e._v("IObjectSerializer has new method, void Initialize(), that has to be implemented")]),e._v(" "),a("li",[e._v("IInterruptableJob removed in favor of context's CancellationToken")])]),e._v(" "),a("p",[a("strong",[e._v("KNOWN ISSUES")])]),e._v(" "),a("ul",[a("li",[e._v("Issues with time zone ids between Windows and Linux, they use different ids for the same zone")]),e._v(" "),a("li",[e._v("No remoting support")]),e._v(" "),a("li",[e._v("Documentation lacking")])]),e._v(" "),a("p",[e._v("Check NuGet for pre-release packages.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/32.35d4940b.js b/assets/js/32.35d4940b.js new file mode 100644 index 000000000..cd9e5ce0d --- /dev/null +++ b/assets/js/32.35d4940b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{406:function(e,n,t){"use strict";t.r(n);var o=t(26),l=Object(o.a)({},(function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Right on the heels of [Quartz.NET 3.0 Alpha 1]({% post_url 2016-08-16-quartznet-3.0-alpha1-released %}) we now have\na small maintenance version. With version 2.4 we are slowing things down with 2.x series and concentrate effors on v3 development.")]),e._v(" "),t("p",[t("strong",[e._v("NEW FEATURE")])]),e._v(" "),t("ul",[t("li",[e._v("Add SQL limit support for MySQLDelegate")]),e._v(" "),t("li",[e._v("Removed dbFailureRetryInterval since it is no longer used")]),e._v(" "),t("li",[e._v("Update Common Logging to v3.3.1")])]),e._v(" "),t("p",[t("strong",[e._v("FIXES")])]),e._v(" "),t("ul",[t("li",[e._v("Batch acquisition can cause early firing of triggers")]),e._v(" "),t("li",[e._v("Should not rely on "),t("code",[e._v("C5.TreeSet")]),e._v(" on HolidayCalendar field serialization")])]),e._v(" "),t("Download")],1)}),[],!1,null,null,null);n.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/33.32a324dc.js b/assets/js/33.32a324dc.js new file mode 100644 index 000000000..c35ca32c3 --- /dev/null +++ b/assets/js/33.32a324dc.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{407:function(t,e,n){"use strict";n.r(e);var s=n(26),o=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("p",[this._v("Minor release that just makes Common.Logging 3.3.1 bound by compilation process\nand not just by NuGet version reference.")]),this._v(" "),e("p",[e("strong",[this._v("FIXES")])]),this._v(" "),e("ul",[e("li",[this._v("Fix Common.Logging version 3.3.1 to be a true binary reference instead of just NuGet dependency")])]),this._v(" "),e("Download")],1)}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/34.4cefe782.js b/assets/js/34.4cefe782.js new file mode 100644 index 000000000..2779c8ae6 --- /dev/null +++ b/assets/js/34.4cefe782.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{408:function(e,t,s){"use strict";s.r(t);var o=s(26),i=Object(o.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("p",[e._v("This is the second alpha of v3. This release fixes problems with schedule signaling when AdoJobStore is in use.\nThis release removes the last bits of Quartz's usage of thread local storage and thus makes async-based operations a lot safer.")]),e._v(" "),s("p",[s("strong",[e._v("FIXES")])]),e._v(" "),s("ul",[s("li",[e._v("fix scheduler signaling not working with AdoJobStore due to thread local storage")]),e._v(" "),s("li",[e._v("thread local state removed altogether")]),e._v(" "),s("li",[e._v("quartz.serializer.type was required even though non-serializing RAMJobStore was in use")]),e._v(" "),s("li",[e._v("JSON serialization incorrectly called serialization callbacks")])]),e._v(" "),s("p",[s("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),s("ul",[s("li",[e._v("IStatefulJob was removed, been obsolete since 2.x")]),e._v(" "),s("li",[e._v("ISemaphore interface now passes Guid requestorId that defines lock owner instead of implicit thread name")])]),e._v(" "),s("p",[s("strong",[e._v("KNOWN ISSUES")])]),e._v(" "),s("ul",[s("li",[e._v("Issues with time zone ids between Windows and Linux, they use different ids for the same zone")]),e._v(" "),s("li",[e._v("No remoting support")]),e._v(" "),s("li",[e._v("Documentation lacking")])]),e._v(" "),s("p",[e._v("Check NuGet for pre-release packages.")])])}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/35.3912f4fb.js b/assets/js/35.3912f4fb.js new file mode 100644 index 000000000..0e44d587f --- /dev/null +++ b/assets/js/35.3912f4fb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{409:function(e,t,r){"use strict";r.r(t);var n=r(26),i=Object(n.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("This release contains mainly bug fixes but because there's a behavioral change in\nDST handling (for the better) that warrants for a minor version number increment.")]),e._v(" "),r("p",[e._v("See "),r("a",{attrs:{href:"https://github.com/quartznet/quartznet/pull/317",target:"_blank",rel:"noopener noreferrer"}},[e._v("the GitHub issue "),r("OutboundLink")],1),e._v(" for details.")]),e._v(" "),r("p",[r("strong",[e._v("FIXES")])]),e._v(" "),r("ul",[r("li",[e._v("Jobs get stuck in the Blocked state after the DB connection is lost in NotifyJobListenersComplete (#282)")]),e._v(" "),r("li",[e._v("Oracle rownum based queries can work wrong after Oracle SQL tuning task has ran (#413)")]),e._v(" "),r("li",[e._v("Handle DST better (#317)")]),e._v(" "),r("li",[e._v("RAMJobStore fails to resume when paused without triggers (#433)")]),e._v(" "),r("li",[e._v('CronExpression doesn\'t properly check the range when an "/interval" is specified (#432)')]),e._v(" "),r("li",[e._v("Fix JobDataMap dirty flag when constructing from existing map (#431)")]),e._v(" "),r("li",[e._v("Store triggers by job in RAMJobStore for better performance (#430)")]),e._v(" "),r("li",[e._v("Create WorkerThread in virtual method (#426)")]),e._v(" "),r("li",[e._v("SqlSelectJobForTrigger is not using primary key join and causes index scan (#407)")])]),e._v(" "),r("Download")],1)}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/36.3b387353.js b/assets/js/36.3b387353.js new file mode 100644 index 000000000..b2daab423 --- /dev/null +++ b/assets/js/36.3b387353.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{410:function(e,t,i){"use strict";i.r(t);var o=i(26),r=Object(o.a)({},(function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[i("p",[i("strong",[e._v("Addition of column required to database")])]),e._v(" "),i("ul",[i("li",[e._v("This release fixes a long standing issue, DailyTimeIntervalTrigger's time zone is now finally persisted to database")]),e._v(" "),i("li",[e._v("This requires running "),i("a",{attrs:{href:"https://github.com/quartznet/quartznet/blob/2.x/database/schema_25_to_26_upgrade.sql",target:"_blank",rel:"noopener noreferrer"}},[e._v("schema_25_to_26_upgrade.sql"),i("OutboundLink")],1),e._v(" to add new column to QRTZ_SIMPROP_TRIGGERS table")])]),e._v(" "),i("p",[e._v("A slight performance boost can also be unlocked when using PostgreSQL by switching PostgreSqlDelegate.")]),e._v(" "),i("p",[i("strong",[e._v("NEW FEATURE")])]),e._v(" "),i("ul",[i("li",[e._v("Add support for eager validation of job scheduling XML file on plugin start (#492)")]),e._v(" "),i("li",[e._v("Add support for extra custom time zone resolver function in TimeZoneUtil (#290)")])]),e._v(" "),i("p",[i("strong",[e._v("FIXES")])]),e._v(" "),i("ul",[i("li",[e._v("CalendarIntervalTrigger's first fire time doesn't consider time zone (#505)")]),e._v(" "),i("li",[e._v("QRTZ_FIRED_TRIGGERS.ENTRY_ID column length too small (#474)")]),e._v(" "),i("li",[e._v("Decrease log level for message when host name is too long (#471)")]),e._v(" "),i("li",[e._v("Quartz should not log transient faults related to azure db connection as errors (#470)")]),e._v(" "),i("li",[e._v("RemotingSchedulerExporter can't create remoting channel on Mono (#464)")]),e._v(" "),i("li",[e._v("Regression in 2.5, TriggerBuilder.UsingJobData(JobDataMap newJobDataMap) should ovewrite existing (#460)")]),e._v(" "),i("li",[e._v("QuartzScheduler.Clear does not clear QRTZ_FIRED_TRIGGERS table (#437)")]),e._v(" "),i("li",[e._v("No wait time between db connection failures with AcquireNextTriggers (#428)")]),e._v(" "),i("li",[e._v("DailyTimeIntervalTriggerImpl prevents altering EndTimeOfDay to a later time of day (#382)")]),e._v(" "),i("li",[e._v("Quartz.CronExpression.IsSatisfiedBy claims to ignore milliseconds but doesn't (#349)")]),e._v(" "),i("li",[e._v("Add back PostgreSqlDelegate to support database LIMIT in trigger acquiring (#318)")]),e._v(" "),i("li",[e._v("Bug in XSD schema: cannot set "),i("misfire-instruction",[e._v("IgnoreMisfirePolicy")]),e._v(" (#280)")],1),e._v(" "),i("li",[e._v("Quartz.Xml.XMLSchedulingDataProcessor uses GetType() instead of typeof(Quartz.Xml.XMLSchedulingDataProcessor) (#277)")]),e._v(" "),i("li",[e._v("With SQLite default isolation level should be set to serializable (#242)")]),e._v(" "),i("li",[e._v("DailyTimeIntervalTrigger's time zone is not persisted into database (#136)")]),e._v(" "),i("li",[e._v("XMLSchedulingDataProcessorPlugin incompatible with StdAdoDelegate when useProperties=true (#44)")]),e._v(" "),i("li",[e._v("Trigger loop encountered using DailyTimeIntervalTrigger across DST start boundary (#332)")])]),e._v(" "),i("Download")],1)}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/37.193bf8a1.js b/assets/js/37.193bf8a1.js new file mode 100644 index 000000000..eb1e0c42f --- /dev/null +++ b/assets/js/37.193bf8a1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{411:function(e,o,n){"use strict";n.r(o);var i=n(26),t=Object(i.a)({},(function(){var e=this,o=e.$createElement,n=e._self._c||o;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("p",[e._v("This is the third alpha of v3. APIs have had some love in form of adding CancellationToken support and\nusing more "),n("code",[e._v("IReadOnlyCollection")]),e._v("s more concisely. Unfortunately we still don't have the story done for\nremote management support (HTTP API).")]),e._v(" "),n("p",[n("strong",[e._v("When using AdoJobStore: make sure to run both 2.6 and 3.0 SQL migration scripts if you are upgrading from 2.5, otherwise just 3.0 migration script")])]),e._v(" "),n("p",[n("strong",[e._v("NEW FEATURE")])]),e._v(" "),n("ul",[n("li",[e._v("support for .NET Standard 2.0 preview (#486)")]),e._v(" "),n("li",[e._v("support for MySQL on .NET Standard via provider 'MySql' (#493)")]),e._v(" "),n("li",[e._v("change SQL database IMAGE types to VARBINARY - requires migration schema_26_to_30.sql")]),e._v(" "),n("li",[e._v("add ISchedulerListener.JobInterrupted(JobKey jobKey, CancellationToken cancellationToken) (#467)")])]),e._v(" "),n("p",[n("strong",[e._v("FIXES")])]),e._v(" "),n("ul",[n("li",[e._v("fix PosgreSQL db provider configuration for .NET Core (#449)")]),e._v(" "),n("li",[e._v("CancellationToken is now supported in async methods (#444)")]),e._v(" "),n("li",[e._v("fix regression with XML schema validation")])]),e._v(" "),n("p",[n("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),n("ul",[n("li",[e._v("possibly breaking, cron expression validation is now stricter (#315 #485)")]),e._v(" "),n("li",[e._v(".NET 4.6 required instead of old 4.5")]),e._v(" "),n("li",[e._v("API methods have been revisited to mainly use "),n("code",[e._v("IReadOnlyCollection")]),e._v(", this hides both "),n("code",[e._v("HashSet")]),e._v("s and "),n("code",[e._v("List")]),e._v("s")]),e._v(" "),n("li",[e._v("LibLog has been hidden as internal (ILog etc), like it was originally intended to be")])]),e._v(" "),n("p",[n("strong",[e._v("KNOWN ISSUES")])]),e._v(" "),n("ul",[n("li",[e._v("Issues with time zone ids between Windows and Linux, they use different ids for the same zone")]),e._v(" "),n("li",[e._v("No remoting support")]),e._v(" "),n("li",[e._v("Documentation lacking")])]),e._v(" "),n("p",[e._v("Check NuGet for pre-release packages.")])])}),[],!1,null,null,null);o.default=t.exports}}]); \ No newline at end of file diff --git a/assets/js/38.83de4ad0.js b/assets/js/38.83de4ad0.js new file mode 100644 index 000000000..bdb296b0e --- /dev/null +++ b/assets/js/38.83de4ad0.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{412:function(e,r,t){"use strict";t.r(r);var i=t(26),o=Object(i.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("This is the first beta of v3. Stabilization and testing has been well underway.")]),e._v(" "),t("p",[t("strong",[e._v("When using AdoJobStore: make sure to run both 2.6 and 3.0 SQL migration scripts if you are upgrading from 2.5, otherwise just 3.0 migration script")])]),e._v(" "),t("p",[t("strong",[e._v("NEW FEATURE")])]),e._v(" "),t("ul",[t("li",[e._v("returned .NET Framework 4.5.2 compatibility to better support library consumers like NServiceBus and MassTransit")]),e._v(" "),t("li",[e._v("netstandard 2.0 is now minimum for .NET Core")]),e._v(" "),t("li",[e._v("support for Microsoft.Data.Sqlite via provider name SQLite-Microsoft, the old provider SQLite also still works")]),e._v(" "),t("li",[e._v("Firebird is supported in .NET Core")]),e._v(" "),t("li",[e._v("Added preliminary support for SQL Server Memory-Optimized tables and Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT")])]),e._v(" "),t("p",[t("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),t("ul",[t("li",[e._v("Jobs and plugins are now in a separate assemblies/NuGet packages Quartz.Jobs and Quartz.Plugins")]),e._v(" "),t("li",[e._v("ADO.NET provider names have been simplified, the provider names are without version, e.g. SqlServer-20 => SqlServer")])]),e._v(" "),t("p",[t("strong",[e._v("KNOWN ISSUES")])]),e._v(" "),t("ul",[t("li",[e._v("Issues with time zone ids between Windows and Linux, they use different ids for the same zone")]),e._v(" "),t("li",[e._v("No remoting support for .NET Core")]),e._v(" "),t("li",[e._v("Documentation lacking")])]),e._v(" "),t("p",[e._v("Check NuGet for pre-release packages.")])])}),[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/39.9607a50c.js b/assets/js/39.9607a50c.js new file mode 100644 index 000000000..abfba4422 --- /dev/null +++ b/assets/js/39.9607a50c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{413:function(e,n,s){"use strict";s.r(n);var i=s(26),t=Object(i.a)({},(function(){var e=this,n=e.$createElement,s=e._self._c||n;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("p",[e._v("This is a maintenance release fixing an issue where misfire handling is being too slow at times. This regression has been present since version 2.4.")]),e._v(" "),s("p",[s("strong",[e._v("NEW FEATURE")])]),e._v(" "),s("ul",[s("li",[e._v("Allow performing misfire handling more frequently than misfireThreshold (#532)")])]),e._v(" "),s("p",[s("strong",[e._v("FIXES")])]),e._v(" "),s("ul",[s("li",[e._v("Incomplete recovery of misfired jobs when using database-specific delegate types (#531)")])]),e._v(" "),s("Download")],1)}),[],!1,null,null,null);n.default=t.exports}}]); \ No newline at end of file diff --git a/assets/js/4.9a469852.js b/assets/js/4.9a469852.js new file mode 100644 index 000000000..270c3a5fb --- /dev/null +++ b/assets/js/4.9a469852.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{341:function(t,e,n){},375:function(t,e,n){"use strict";n(341)},523:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(375),n(26)),p=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/40.e5ff7906.js b/assets/js/40.e5ff7906.js new file mode 100644 index 000000000..dcfcc9a22 --- /dev/null +++ b/assets/js/40.e5ff7906.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{414:function(e,t,o){"use strict";o.r(t);var r=o(26),i=Object(r.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("The wait is over, Quartz.NET 3.0 is here with .NET Core support and async/await!")]),e._v(" "),o("p",[e._v("A big thank you goes to "),o("a",{attrs:{href:"https://github.com/mjrousos",target:"_blank",rel:"noopener noreferrer"}},[e._v("Mike Rousos"),o("OutboundLink")],1),e._v(" who really made it possible to get Quartz.NET working on .NET Core.\n"),o("a",{attrs:{href:"https://github.com/danielmarbach",target:"_blank",rel:"noopener noreferrer"}},[e._v("Daniel Marbach"),o("OutboundLink")],1),e._v(" also contributed a lot with ideas and code to async side.\nAnd of course never forgetting the community members that have provided feedback and fixes.")]),e._v(" "),o("p",[e._v("Please see the "),o("RouterLink",{attrs:{to:"/documentation/quartz-3.x/migration-guide.html"}},[e._v("migration guide")]),e._v(".")],1),e._v(" "),o("p",[o("strong",[e._v("NEW FEATURE")])]),e._v(" "),o("ul",[o("li",[e._v("Task based jobs with async/await support, internals work in async/await manner")]),e._v(" "),o("li",[e._v("Support .NET Core / netstandard 2.0 and .NET Framework 4.5.2 and later")]),e._v(" "),o("li",[e._v("Support for Microsoft.Data.Sqlite via provider name SQLite-Microsoft, the old provider SQLite also still works")]),e._v(" "),o("li",[e._v("Added preliminary support for SQL Server Memory-Optimized tables and Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT")]),e._v(" "),o("li",[e._v("Common.Logging removed from dependencies")]),e._v(" "),o("li",[e._v("C5 Collections removed from ILMerge process, no longer needed")]),e._v(" "),o("li",[e._v("Add support for eager validation of job scheduling XML file on plugin start")]),e._v(" "),o("li",[e._v("Add support for extra custom time zone resolver function in TimeZoneUtil")])]),e._v(" "),o("p",[o("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),o("ul",[o("li",[e._v("Jobs and plugins are now in a separate assemblies/NuGet packages Quartz.Jobs and Quartz.Plugins")]),e._v(" "),o("li",[e._v("ADO.NET provider names have been simplified, the provider names are without version, e.g. SqlServer-20 => SqlServer")]),e._v(" "),o("li",[e._v("API methods have been revisited to mainly use "),o("code",[e._v("IReadOnlyCollection")]),e._v(", this hides both "),o("code",[e._v("HashSet")]),e._v("s and "),o("code",[e._v("List")]),e._v("s")]),e._v(" "),o("li",[e._v("LibLog has been hidden as internal (ILog etc), like it was originally intended to be")]),e._v(" "),o("li",[e._v("SimpleThreadPool is gone, old owned threads are gone")]),e._v(" "),o("li",[e._v("Scheduler methods have been changed to be Task based, remember to await them")]),e._v(" "),o("li",[e._v("IJob interface now returns a task")]),e._v(" "),o("li",[e._v("Some IList properties have been changed to IReadOnlyList to properly reflect intent")]),e._v(" "),o("li",[e._v("SQL Server CE support has been dropped")]),e._v(" "),o("li",[e._v("DailyCalendar uses now datetimes for excluded dates and has ISet interface to access them")]),e._v(" "),o("li",[e._v("IObjectSerializer has new method, void Initialize(), that has to be implemented")]),e._v(" "),o("li",[e._v("IInterruptableJob removed in favor of context's CancellationToken")])]),e._v(" "),o("p",[o("strong",[e._v("KNOWN ISSUES")])]),e._v(" "),o("ul",[o("li",[e._v("Issues with time zone ids between Windows and Linux, they use different ids for the same zone")]),e._v(" "),o("li",[e._v("No remoting support for .NET Core")])]),e._v(" "),o("Download")],1)}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/41.7affac67.js b/assets/js/41.7affac67.js new file mode 100644 index 000000000..876611437 --- /dev/null +++ b/assets/js/41.7affac67.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{415:function(t,e,a){"use strict";a.r(e);var n=a(26),s=Object(n.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("This is a bug fix release that fixes cron expression parsing bug and reverts IRemotableQuartzScheduler\ninterface back to its original form without Tasks and CancellationTokens - so that's it's actually usable\nthrough .NET Remoting infrastructure. Now zip packing is also back and includes Quartz.Server.")]),t._v(" "),a("p",[a("strong",[t._v("FIXES")])]),t._v(" "),a("ul",[a("li",[t._v("Create zip package as part of release, including Quartz.Server (#572)")]),t._v(" "),a("li",[t._v('A specific CronExpression fails with "Input string was not in a correct format." (#568)')]),t._v(" "),a("li",[t._v("Cannot use remoting due to Task and CancellationToken signatures (#571)")])]),t._v(" "),a("Download")],1)}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/42.00fe8e23.js b/assets/js/42.00fe8e23.js new file mode 100644 index 000000000..89d853c7d --- /dev/null +++ b/assets/js/42.00fe8e23.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{416:function(t,s,e){"use strict";e.r(s);var i=e(26),l=Object(i.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("p",[this._v("This is a minor fix release that fixes single issue that still prevented full usage of remoting.")]),this._v(" "),s("p",[s("strong",[this._v("FIXES")])]),this._v(" "),s("ul",[s("li",[this._v("Mark ReadOnlyCompatibleHashSet as serializable (#576)")])]),this._v(" "),s("Download")],1)}),[],!1,null,null,null);s.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/43.4f7d0962.js b/assets/js/43.4f7d0962.js new file mode 100644 index 000000000..20e51b85e --- /dev/null +++ b/assets/js/43.4f7d0962.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{417:function(e,t,r){"use strict";r.r(t);var i=r(26),n=Object(i.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("This is a minor fix release.")]),e._v(" "),r("p",[r("strong",[e._v("FIXES")])]),e._v(" "),r("ul",[r("li",[e._v("XML scheduling requires write access to source XML file (#591)")]),e._v(" "),r("li",[e._v("Improve listener error handling (#589)")]),e._v(" "),r("li",[e._v("SQL command parameters are not defined in 'IsTriggerStillPresent' method (#579)")]),e._v(" "),r("li",[e._v("Source distribution couldn't be built with build.cmd/.sh when no .git directory present (#596)")]),e._v(" "),r("li",[e._v("Currently executing jobs cannot be retrieved via remoting (#580)")])]),e._v(" "),r("Download")],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/44.fd58bb75.js b/assets/js/44.fd58bb75.js new file mode 100644 index 000000000..63d22c661 --- /dev/null +++ b/assets/js/44.fd58bb75.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[44],{418:function(e,s,t){"use strict";t.r(s);var a=t(26),n=Object(a.a)({},(function(){var e=this,s=e.$createElement,t=e._self._c||s;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("This release fixes a nasty memory leak caused by QuartzSchedulerThread sharing its CancellationTokenSource with calls it makes.\nEveryone using 3.x is advised to upgrade.")]),e._v(" "),t("p",[t("strong",[e._v("FIXES")])]),e._v(" "),t("ul",[t("li",[e._v("Memory leak caused by CancellationTokenSource sharing (#600)")]),e._v(" "),t("li",[e._v("tables_oracle.sql should use NUMBER(19) instead of NUMBER(13) for long properties (#598)")])]),e._v(" "),t("Download")],1)}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/45.07c03278.js b/assets/js/45.07c03278.js new file mode 100644 index 000000000..d4b877f53 --- /dev/null +++ b/assets/js/45.07c03278.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{419:function(e,s,t){"use strict";t.r(s);var r=t(26),n=Object(r.a)({},(function(){var e=this,s=e.$createElement,t=e._self._c||s;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("This is a maintenance release fixing some bugs.")]),e._v(" "),t("p",[t("strong",[e._v("FIXES")])]),e._v(" "),t("ul",[t("li",[e._v("trigger loop encountered using DailyTimeIntervalTrigger across DST start boundary (#610)")]),e._v(" "),t("li",[e._v("tables_oracle.sql should use NUMBER(19) instead of NUMBER(13) for long properties (#598)")]),e._v(" "),t("li",[e._v("XML scheduling requires write access to source XML file (#591)")])]),e._v(" "),t("Download")],1)}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/46.6b0f5704.js b/assets/js/46.6b0f5704.js new file mode 100644 index 000000000..191884dfd --- /dev/null +++ b/assets/js/46.6b0f5704.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{420:function(e,r,s){"use strict";s.r(r);var t=s(26),a=Object(t.a)({},(function(){var e=this,r=e.$createElement,s=e._self._c||r;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("p",[e._v("This release fixes couple bugs and adds support for .NET Core version of Oracle's managed data access library.")]),e._v(" "),s("p",[s("strong",[e._v("NEW FEATURE")])]),e._v(" "),s("ul",[s("li",[e._v("Support Oracle.ManagedDataAccess.Core (#609)")])]),e._v(" "),s("p",[s("strong",[e._v("FIXES")])]),e._v(" "),s("ul",[s("li",[e._v("trigger loop encountered using DailyTimeIntervalTrigger across DST start boundary (#610)")]),e._v(" "),s("li",[e._v("Missing ConfigureAwait(false) in some parts of code (#618)")])]),e._v(" "),s("Download")],1)}),[],!1,null,null,null);r.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/47.1b566e3b.js b/assets/js/47.1b566e3b.js new file mode 100644 index 000000000..514bc0b2e --- /dev/null +++ b/assets/js/47.1b566e3b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[47],{421:function(e,o,r){"use strict";r.r(o);var t=r(26),n=Object(t.a)({},(function(){var e=this,o=e.$createElement,r=e._self._c||o;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("This release fixes a nasty bug with JSON calendar database serialization and .NET Core SQL Server client libraries\nhave been updated to mitigiate possible hangs when connection drops occur.")]),e._v(" "),r("p",[e._v("Also some other minor bugs have been also addressed.")]),e._v(" "),r("p",[e._v("You should now be able to debug into Quartz.NET sources with added SourceLink support.")]),e._v(" "),r("p",[r("strong",[e._v("NEW FEATURE")])]),e._v(" "),r("ul",[r("li",[e._v("Add SourceLink support (#642)")]),e._v(" "),r("li",[e._v("Make JobInterrupted method virtual in class SchedulerListenerSupport (#631)")])]),e._v(" "),r("p",[r("strong",[e._v("FIXES")])]),e._v(" "),r("ul",[r("li",[e._v("Trigger group can be left as paused when all triggers have been removed (#641)")]),e._v(" "),r("li",[e._v("PlatformNotSupportedException on RaspberryPi (Windows IoT) (#630)")]),e._v(" "),r("li",[e._v("JSON serialisation returning defaults for derived calendar settings (#634)")]),e._v(" "),r("li",[e._v(".NET Core version not able to recover from DB connection drops (#637)")])]),e._v(" "),r("Download")],1)}),[],!1,null,null,null);o.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/48.31882e6a.js b/assets/js/48.31882e6a.js new file mode 100644 index 000000000..3bf7dcbba --- /dev/null +++ b/assets/js/48.31882e6a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{422:function(e,r,n){"use strict";n.r(r);var o=n(26),t=Object(o.a)({},(function(){var e=this,r=e.$createElement,n=e._self._c||r;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("p",[e._v("This release brings .NET Core 2.1 version of example server and adds new plugin\nQuartz.Plugins.TimeZoneConverter which allows usage of "),n("a",{attrs:{href:"https://github.com/mj1856/TimeZoneConverter",target:"_blank",rel:"noopener noreferrer"}},[e._v("TimeZoneConverter library"),n("OutboundLink")],1),e._v(" to get consistent time zone id parsing between\nLinux and Windows.")]),e._v(" "),n("p",[e._v("There are also some bug fixes related to AdoJobStore.")]),e._v(" "),n("p",[n("strong",[e._v("NEW FEATURE")])]),e._v(" "),n("ul",[n("li",[e._v("Add .NET Core 2.1 version of example server (#682)")]),e._v(" "),n("li",[e._v("New plugin "),n("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Plugins.TimeZoneConverter",target:"_blank",rel:"noopener noreferrer"}},[e._v("Quartz.Plugins.TimeZoneConverter"),n("OutboundLink")],1),e._v(" which allows usage of TimeZoneConverter library (#647)")])]),e._v(" "),n("p",[n("strong",[e._v("FIXES")])]),e._v(" "),n("ul",[n("li",[e._v("Added transient codes from EF into new JobStore (#681)")]),e._v(" "),n("li",[e._v("Parametrized queries produced by ReplaceTablePrefix should be cached (#651)")]),e._v(" "),n("li",[e._v("Use TypeNameHandling.Auto for JsonObjectSerializer (#621)")]),e._v(" "),n("li",[e._v("Fix a race condition that could cause duplicate trigger firings (#690)")]),e._v(" "),n("li",[e._v("ISchedulerListener.JobScheduled not called when scheduling multiple jobs (ScheduleJobs) (#678)")])]),e._v(" "),n("Download")],1)}),[],!1,null,null,null);r.default=t.exports}}]); \ No newline at end of file diff --git a/assets/js/49.350a7768.js b/assets/js/49.350a7768.js new file mode 100644 index 000000000..635313a0e --- /dev/null +++ b/assets/js/49.350a7768.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{423:function(e,t,s){"use strict";s.r(t);var r=s(26),n=Object(r.a)({},(function(){var e=this.$createElement,t=this._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("p",[this._v("The Quartz.NET website has been refreshed using "),t("a",{attrs:{href:"https://vuepress.vuejs.org/",target:"_blank",rel:"noopener noreferrer"}},[this._v("VuePress"),t("OutboundLink")],1),this._v(".")]),this._v(" "),t("p",[this._v("The new format should make the documentation more modern, easier to navigate and more compatible with mobile devices.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/5.b59b1de3.js b/assets/js/5.b59b1de3.js new file mode 100644 index 000000000..2e6266f41 --- /dev/null +++ b/assets/js/5.b59b1de3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{342:function(t,e,a){},376:function(t,e,a){"use strict";a(342)},386:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(376),a(26)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/50.511e3e44.js b/assets/js/50.511e3e44.js new file mode 100644 index 000000000..147c80676 --- /dev/null +++ b/assets/js/50.511e3e44.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{424:function(e,r,t){"use strict";t.r(r);var n=t(26),a=Object(n.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h2",{attrs:{id:"quartz-net-3-1-beta-1-released"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#quartz-net-3-1-beta-1-released"}},[e._v("#")]),e._v(" Quartz.NET 3.1 beta 1 Released")]),e._v(" "),t("p",[e._v("The wait is almost over, after more than two years of hiatus, Quartz.NET 3.1 beta 1 is here with exciting new features. This release concentrates on performance and bringing support to de facto Microsoft libraries like dependency injection and ASP.NET Core hosting.")]),e._v(" "),t("h3",{attrs:{id:"support-for-asp-net-core-dependency-injection-and-hosted-services"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#support-for-asp-net-core-dependency-injection-and-hosted-services"}},[e._v("#")]),e._v(" Support for ASP.NET Core Dependency Injection and Hosted Services")]),e._v(" "),t("p",[e._v("You can find the revisited packages as:")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Extensions.DependencyInjection/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Quartz.Extensions.DependencyInjection"),t("OutboundLink")],1),e._v(" - Microsoft DI integration")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.AspNetCore",target:"_blank",rel:"noopener noreferrer"}},[e._v("Quartz.AspNetCore"),t("OutboundLink")],1),e._v(" - ASP.NET Core integration")])]),e._v(" "),t("p",[e._v("I would like to thank both "),t("a",{attrs:{href:"https://github.com/fglaeser",target:"_blank",rel:"noopener noreferrer"}},[e._v("Facundo Glaeser"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://github.com/zlzforever",target:"_blank",rel:"noopener noreferrer"}},[e._v("Lewis Zou"),t("OutboundLink")],1),e._v(" for working with the new integration packages and their logistics.")]),e._v(" "),t("p",[e._v("The best resource the see the new DI integration in progress is to head to "),t("a",{attrs:{href:"https://github.com/quartznet/quartznet/tree/master/src/Quartz.Examples.AspNetCore",target:"_blank",rel:"noopener noreferrer"}},[e._v("the example ASP.NET Core application"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h3",{attrs:{id:"index-and-query-performance-improvements"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#index-and-query-performance-improvements"}},[e._v("#")]),e._v(" Index and query performance improvements")]),e._v(" "),t("p",[e._v("A big change on the persistent store side is that now SQL queries use parametrized scheduler name, which allows database server to reuse query plans and use indexes more optimally. This will help especially clusters which have large number of nodes. The SQL server indexes were also revisited and their amount reduced by using smarter covering indexes.")]),e._v(" "),t("p",[e._v("See the "),t("a",{attrs:{href:"https://github.com/quartznet/quartznet/blob/42af207fa815789936e8e4ce5ebd4516a23d7c72/database/tables/tables_sqlServer.sql#L349-L388",target:"_blank",rel:"noopener noreferrer"}},[e._v("updated create index definition"),t("OutboundLink")],1),e._v(" for more details.")]),e._v(" "),t("p",[e._v("There are also some minor bug fixes present.")]),e._v(" "),t("h3",{attrs:{id:"known-issues"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#known-issues"}},[e._v("#")]),e._v(" Known Issues")]),e._v(" "),t("p",[e._v("The documentation for the new integration features is still being worked on.")]),e._v(" "),t("h3",{attrs:{id:"github-issues"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[e._v("#")]),e._v(" GitHub Issues")]),e._v(" "),t("p",[t("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),t("ul",[t("li",[e._v("minimum supported .NET Full Framework is now 4.6.1")])]),e._v(" "),t("p",[t("strong",[e._v("NEW FEATURE")])]),e._v(" "),t("ul",[t("li",[e._v("Microsoft DI integration via package Quartz.Extensions.DependencyInjection (also allows briding to Microsoft Logging)")]),e._v(" "),t("li",[e._v("ASP.NET Core / Hosting integration and health checks via revisited NuGet package Quartz.AspNetCore (thank you zlzforever for contributing the work)")]),e._v(" "),t("li",[e._v("Introduced a config parameter "),t("code",[e._v("ClusterCheckinMisfireThreshold")]),e._v(" (#692)")]),e._v(" "),t("li",[e._v("Giving meaningful names to examples folders (#701)")]),e._v(" "),t("li",[e._v("Added search patterns/sub directory search to directoty scanner job (#411, #708)")]),e._v(" "),t("li",[e._v("Fluent interface for scheduler configuration (#791)")]),e._v(" "),t("li",[e._v("Support every nth week in cron expression (#790)")]),e._v(" "),t("li",[e._v("Enable SQLite job store provider for NetStandard (#802)")]),e._v(" "),t("li",[e._v("Add configurable params for StdRowLockSemaphore for Failure obtaining db row lock")]),e._v(" "),t("li",[e._v("SchedName added to queries as sql paramteter (#818)")]),e._v(" "),t("li",[e._v("Server, example and test projects upgraded to user .NET Core 3.1")]),e._v(" "),t("li",[e._v("Nullable reference type annotations have been enabled")]),e._v(" "),t("li",[e._v("Symbols are now provided as a separate NuGet symbol package (snupkg)")]),e._v(" "),t("li",[e._v("SQL Server indexes have been fine-tuned, redudancies were removed and you can follow the current scripts to update to latest version of them")])]),e._v(" "),t("p",[t("strong",[e._v("FIXES")])]),e._v(" "),t("ul",[t("li",[e._v("Allow binary serialization for DirectoryScanJob data (#658)")]),e._v(" "),t("li",[e._v("LibLog - Fixed NLog + Log4net callsite. Added support for NLog structured logging. Optimized Log4net-logger (#705)")]),e._v(" "),t("li",[e._v("Upgrade LibLog to latest version (#749)")]),e._v(" "),t("li",[e._v("RAMJobStore performance improvements (#718, #719, #720)")]),e._v(" "),t("li",[e._v("General performance improvements (#725, #723, #727)")]),e._v(" "),t("li",[e._v("GetTimeBefore() and GetFinalFireTime() should throw NotImplementedException instead of returning null (#731)")]),e._v(" "),t("li",[e._v("Switch to official TimeZoneConverter NuGet package (#739)")]),e._v(" "),t("li",[e._v("Remove invalid TimeSpanParseRule.Days (#782)")]),e._v(" "),t("li",[e._v("Update tables_sqlServer.sql to follow current SQL syntax and structures (#787)")]),e._v(" "),t("li",[e._v("Fix China Standard Time mapping in TimeZoneUtil.cs (#765)")]),e._v(" "),t("li",[e._v("Release BLOCKED triggers in ReleaseAcquiredTrigger (#741 #800)")]),e._v(" "),t("li",[e._v("DailyTimeIntervalTrigger failed to set endingDailyAfterCount = 1")]),e._v(" "),t("li",[e._v("CronTrigger: cover all valid misfire policies, and provide a sensible default and logging when seeing an invalid one")])]),e._v(" "),t("Download")],1)}),[],!1,null,null,null);r.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/51.86078c87.js b/assets/js/51.86078c87.js new file mode 100644 index 000000000..d58d7a8ce --- /dev/null +++ b/assets/js/51.86078c87.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[51],{425:function(e,t,s){"use strict";s.r(t);var r=s(26),a=Object(r.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("h2",{attrs:{id:"quartz-net-3-1-beta-2-released"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#quartz-net-3-1-beta-2-released"}},[e._v("#")]),e._v(" Quartz.NET 3.1 beta 2 Released")]),e._v(" "),s("p",[e._v("The wait is almost over, after more than two years of hiatus, Quartz.NET 3.1 beta 2 is here with exciting new features.\nThis release builds on top of "),s("RouterLink",{attrs:{to:"/2020/07/08/quartznet-3-1-beta-1-released/"}},[e._v("beta 1")]),e._v(" adding more fixes and improvements. Read the "),s("RouterLink",{attrs:{to:"/2020/07/08/quartznet-3-1-beta-1-released/"}},[e._v("beta 1 release notes")]),e._v(" to know more.")],1),e._v(" "),s("h3",{attrs:{id:"known-issues"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#known-issues"}},[e._v("#")]),e._v(" Known Issues")]),e._v(" "),s("p",[e._v("The documentation for the new integration features is still being worked on.")]),e._v(" "),s("h3",{attrs:{id:"github-issues"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[e._v("#")]),e._v(" GitHub Issues")]),e._v(" "),s("p",[s("strong",[e._v("NEW FEATURE")])]),e._v(" "),s("ul",[s("li",[e._v("DI configuration now supports adding scheduler, job and trigger listeners (#877)")]),e._v(" "),s("li",[e._v('DI configuration now processes appsettings.json section "Quartz" looking for key value pairs (#877)')]),e._v(" "),s("li",[e._v("Use Microsoft.Data.SqlClient as SQL Server connection library (#839)")])]),e._v(" "),s("p",[s("strong",[e._v("FIXES")])]),e._v(" "),s("ul",[s("li",[e._v("Fix potential scheduler deadlock caused by changed lock request id inside ExecuteInNonManagedTXLock (#794)")]),e._v(" "),s("li",[e._v("Ensure NuGet.exe is part of produced zip to ensure build works (#881)")]),e._v(" "),s("li",[e._v("JobDataMap with enum values persisted as JSON can now be set back to job members via PropertySettingJobFactory (#770)")]),e._v(" "),s("li",[e._v("Ensure GetScheduleBuilder for triggers respects IgnoreMisfirePolicy (#750)")]),e._v(" "),s("li",[e._v("Remove cron expression validation from XML schema and rely on CronExpression itself (#729)")])]),e._v(" "),s("Download")],1)}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/52.b04217a8.js b/assets/js/52.b04217a8.js new file mode 100644 index 000000000..30827b887 --- /dev/null +++ b/assets/js/52.b04217a8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[52],{426:function(e,t,a){"use strict";a.r(t);var s=a(26),r=Object(s.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h2",{attrs:{id:"quartz-net-3-1-beta-3-released"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#quartz-net-3-1-beta-3-released"}},[e._v("#")]),e._v(" Quartz.NET 3.1 beta 3 Released")]),e._v(" "),a("p",[e._v("The wait is almost over, after more than two years of hiatus, Quartz.NET 3.1 beta 2 is here with exciting new features.\nThis release builds on top of beta 1 and beta 2 adding more fixes and improvements.")]),e._v(" "),a("p",[e._v("Read the "),a("RouterLink",{attrs:{to:"/2020/07/08/quartznet-3-1-beta-1-released/"}},[e._v("beta 1 release notes")]),e._v(" and "),a("RouterLink",{attrs:{to:"/2020/07/14/quartznet-3-1-beta-2-released/"}},[e._v("beta 2 release notes")]),e._v(" to know more.")],1),e._v(" "),a("h3",{attrs:{id:"known-issues"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#known-issues"}},[e._v("#")]),e._v(" Known Issues")]),e._v(" "),a("p",[e._v("The documentation for the new integration features is still being worked on.")]),e._v(" "),a("h3",{attrs:{id:"github-issues"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[e._v("#")]),e._v(" GitHub Issues")]),e._v(" "),a("p",[a("strong",[e._v("NEW FEATURE")])]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[e._v("* Upgrade MySqlConnector to 1.0 (namespace has changed) (#890)\n* Support Microsoft.Extensions.Logging.Abstractions (#756)\n* Support Microsoft.Data.SQLite with full framework (#893)\n* Support custom calendar JSON serialization (#697)\n")])])]),a("p",[a("strong",[e._v("FIXES")])]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[e._v("* Remove internal dependencies from examples (#742)\n* Properly assign MaxConcurrency in CreateVolatileScheduler (#726) \n")])])]),a("Download")],1)}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/53.d4849106.js b/assets/js/53.d4849106.js new file mode 100644 index 000000000..b97257c8a --- /dev/null +++ b/assets/js/53.d4849106.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[53],{427:function(t,e,n){"use strict";n.r(e);var s=n(26),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("Redirect",{attrs:{to:"/2020/07/24/quartznet-3-1-released"}})],1)}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/54.568a20d9.js b/assets/js/54.568a20d9.js new file mode 100644 index 000000000..59914b5e2 --- /dev/null +++ b/assets/js/54.568a20d9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[54],{428:function(e,t,r){"use strict";r.r(t);var a=r(26),n=Object(a.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[e._v("This release concentrates on performance and bringing support for standard integrations.\nQuartz 3.1 supports "),r("code",[e._v("netstandard2.0")]),e._v(" and "),r("code",[e._v("net461")]),e._v(" targets (for integrations they may be different).")]),e._v(" "),r("p"),r("div",{staticClass:"table-of-contents"},[r("ul",[r("li",[r("a",{attrs:{href:"#new-integrations"}},[e._v("New Integrations")]),r("ul",[r("li",[r("a",{attrs:{href:"#support-for-asp-net-core-dependency-injection-and-hosted-services"}},[e._v("Support for ASP.NET Core Dependency Injection and Hosted Services")])]),r("li",[r("a",{attrs:{href:"#opentelemetry-integration"}},[e._v("OpenTelemetry Integration")])])])]),r("li",[r("a",{attrs:{href:"#database"}},[e._v("Database")]),r("ul",[r("li",[r("a",{attrs:{href:"#better-indexes-for-sql-server-and-smarter-parametrized-queries"}},[e._v("Better Indexes for SQL Server and smarter parametrized queries")])]),r("li",[r("a",{attrs:{href:"#bug-fix-for-cluster-locking"}},[e._v("Bug fix for cluster locking")])]),r("li",[r("a",{attrs:{href:"#microsoft-data-sqlclient-as-sql-server-connection-library"}},[e._v("Microsoft.Data.SqlClient as SQL Server connection library")])]),r("li",[r("a",{attrs:{href:"#upgrade-mysqlconnector-to-1-0-namespace-has-changed"}},[e._v("Upgrade MySqlConnector to 1.0 (namespace has changed)")])])])]),r("li",[r("a",{attrs:{href:"#known-issues"}},[e._v("Known Issues")])]),r("li",[r("a",{attrs:{href:"#github-issues"}},[e._v("GitHub Issues")])])])]),r("p"),e._v(" "),r("h2",{attrs:{id:"new-integrations"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#new-integrations"}},[e._v("#")]),e._v(" New Integrations")]),e._v(" "),r("h3",{attrs:{id:"support-for-asp-net-core-dependency-injection-and-hosted-services"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#support-for-asp-net-core-dependency-injection-and-hosted-services"}},[e._v("#")]),e._v(" Support for ASP.NET Core Dependency Injection and Hosted Services")]),e._v(" "),r("p",[e._v("New NuGet packages "),r("a",{attrs:{href:"/documentation/quartz-3.x/packages/aspnet-core-integration"}},[e._v("ASP.NET Core Integration")]),e._v(" and "),r("a",{attrs:{href:"/documentation/quartz-3.x/packages/microsoft-di-integration"}},[e._v("Quartz.Extensions.DependencyInjection")]),e._v("\nfinally bring built-in support for integrating Quartz.NET with reliable manner with the Microsoft DI container and hosted services infrastructure.")]),e._v(" "),r("p",[e._v("The best resource the see the new DI integration in progress is to head to "),r("a",{attrs:{href:"https://github.com/quartznet/quartznet/tree/master/src/Quartz.Examples.AspNetCore",target:"_blank",rel:"noopener noreferrer"}},[e._v("the example ASP.NET Core application"),r("OutboundLink")],1),e._v(".")]),e._v(" "),r("p",[e._v("I would like to thank both "),r("a",{attrs:{href:"https://github.com/fglaeser",target:"_blank",rel:"noopener noreferrer"}},[e._v("Facundo Glaeser"),r("OutboundLink")],1),e._v(" and "),r("a",{attrs:{href:"https://github.com/zlzforever",target:"_blank",rel:"noopener noreferrer"}},[e._v("Lewis Zou"),r("OutboundLink")],1),e._v(" for working with the new integration packages and their logistics.")]),e._v(" "),r("h3",{attrs:{id:"opentelemetry-integration"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#opentelemetry-integration"}},[e._v("#")]),e._v(" OpenTelemetry Integration")]),e._v(" "),r("p",[e._v("New experimental NuGet package "),r("RouterLink",{attrs:{to:"/documentation/quartz-3.x/packages/opentelemetry-integration.html"}},[e._v("Quartz.OpenTelemetry.Instrumentation")]),e._v(" brings support for emerging OpenTelemetry standard.")],1),e._v(" "),r("p",[e._v("First version of integration is able transmit job execution ("),r("code",[e._v("Started")]),e._v(", "),r("code",[e._v("Ended")]),e._v(", "),r("code",[e._v("Exception")]),e._v(") information to exporters. With this infrastructure is should also be easier to implement job history\nusing battle-tested log backends for storing data. "),r("a",{attrs:{href:"https://github.com/quartznet/quartznet/tree/master/src/Quartz.Examples.AspNetCore",target:"_blank",rel:"noopener noreferrer"}},[e._v("The example ASP.NET Core application"),r("OutboundLink")],1),e._v(" integrates\nwith Jaeger and transmits this data.")]),e._v(" "),r("h2",{attrs:{id:"database"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#database"}},[e._v("#")]),e._v(" Database")]),e._v(" "),r("h3",{attrs:{id:"better-indexes-for-sql-server-and-smarter-parametrized-queries"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#better-indexes-for-sql-server-and-smarter-parametrized-queries"}},[e._v("#")]),e._v(" Better Indexes for SQL Server and smarter parametrized queries")]),e._v(" "),r("p",[e._v("A big change on the persistent store side is that now SQL queries use parametrized scheduler name, which allows database server to reuse query plans and use indexes more optimally.\nThis will help especially clusters which have large number of nodes. The SQL server indexes were also revisited and their amount reduced by using smarter covering indexes.")]),e._v(" "),r("p",[e._v("See the "),r("a",{attrs:{href:"https://github.com/quartznet/quartznet/blob/42af207fa815789936e8e4ce5ebd4516a23d7c72/database/tables/tables_sqlServer.sql#L349-L388",target:"_blank",rel:"noopener noreferrer"}},[e._v("updated create index definition"),r("OutboundLink")],1),e._v(" for more details.")]),e._v(" "),r("div",{staticClass:"custom-block tip"},[r("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),r("p",[e._v("You need to re-run the index script to take advantage of changes, this will drop old indexes and rebuild/create new ones, it can be time-consuming!")])]),e._v(" "),r("h3",{attrs:{id:"bug-fix-for-cluster-locking"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#bug-fix-for-cluster-locking"}},[e._v("#")]),e._v(" Bug fix for cluster locking")]),e._v(" "),r("p",[e._v("There is also a very important bug fix present for lock handling on retries. There was a possibility for a deadlock in cluster's database lock handling in some situations.")]),e._v(" "),r("h3",{attrs:{id:"microsoft-data-sqlclient-as-sql-server-connection-library"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#microsoft-data-sqlclient-as-sql-server-connection-library"}},[e._v("#")]),e._v(" Microsoft.Data.SqlClient as SQL Server connection library")]),e._v(" "),r("p",[e._v("Quartz now uses "),r("a",{attrs:{href:"https://www.nuget.org/packages/Microsoft.Data.SqlClient/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Microsoft.Data.SqlClient"),r("OutboundLink")],1),e._v(" as the connection library for SQL Server as it's the one going to get new features.\nIt is dependency for Quartz library (for now) so you shouldn't need to do any manual install steps.")]),e._v(" "),r("h3",{attrs:{id:"upgrade-mysqlconnector-to-1-0-namespace-has-changed"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#upgrade-mysqlconnector-to-1-0-namespace-has-changed"}},[e._v("#")]),e._v(" Upgrade MySqlConnector to 1.0 (namespace has changed)")]),e._v(" "),r("p",[e._v("You need to use the latest "),r("a",{attrs:{href:"https://www.nuget.org/packages/MySqlConnector/",target:"_blank",rel:"noopener noreferrer"}},[e._v("MySqlConnector 1.0.0"),r("OutboundLink")],1),e._v(" in order to use with default Quartz configuration.\nAs the namespace for library has changed it's not backwards compatible.\nIf you need to use the old version, you should manually register DB provider with the old details.")]),e._v(" "),r("h2",{attrs:{id:"known-issues"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#known-issues"}},[e._v("#")]),e._v(" Known Issues")]),e._v(" "),r("p",[e._v("No known issues. Documentation might require additions and community contributions are welcomed. Edits should be easy now with the new publishing framework.")]),e._v(" "),r("h2",{attrs:{id:"github-issues"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[e._v("#")]),e._v(" GitHub Issues")]),e._v(" "),r("p",[r("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),r("ul",[r("li",[e._v("minimum supported .NET Full Framework is now 4.6.1")]),e._v(" "),r("li",[e._v("changed SQL commands format in "),r("code",[e._v("Quartz.Impl.AdoJobStore.JobStoreSupport")]),e._v(" (see also "),r("a",{attrs:{href:"https://github.com/quartznet/quartznet/pull/818",target:"_blank",rel:"noopener noreferrer"}},[e._v("#818"),r("OutboundLink")],1),e._v("). Affected are only schedulers that use customized configurations of SQL commands in "),r("code",[e._v("Quartz.Impl.AdoJobStore.JobStoreSupport")]),e._v(", e.g. "),r("code",[e._v("SelectWithLockSQL")]),e._v(". Migration example:")])]),e._v(" "),r("div",{staticClass:"language-xml extra-class"},[r("pre",{pre:!0,attrs:{class:"language-xml"}},[r("code",[r("span",{pre:!0,attrs:{class:"token comment"}},[e._v("\x3c!-- Quartz <=3.0.7 --\x3e")]),e._v("\n"),r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("<")]),e._v("item")]),e._v(" "),r("span",{pre:!0,attrs:{class:"token attr-name"}},[e._v("key")]),r("span",{pre:!0,attrs:{class:"token attr-value"}},[r("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[e._v("=")]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v('"')]),e._v("quartz.jobStore.selectWithLockSQL"),r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v('"')])]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(">")])]),e._v("SELECT * FROM {0}LOCKS WITH (UPDLOCK,ROWLOCK) WHERE SCHED_NAME = {1} AND LOCK_NAME = @lockName"),r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("")])]),e._v("\n"),r("span",{pre:!0,attrs:{class:"token comment"}},[e._v("\x3c!-- Quartz >=3.1.0 --\x3e")]),e._v("\n"),r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("<")]),e._v("item")]),e._v(" "),r("span",{pre:!0,attrs:{class:"token attr-name"}},[e._v("key")]),r("span",{pre:!0,attrs:{class:"token attr-value"}},[r("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[e._v("=")]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v('"')]),e._v("quartz.jobStore.selectWithLockSQL"),r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v('"')])]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(">")])]),e._v("SELECT * FROM {0}LOCKS WITH (UPDLOCK,ROWLOCK) WHERE SCHED_NAME = @schedulerName AND LOCK_NAME = @lockName"),r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token tag"}},[r("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("")])]),e._v("\n")])])]),r("p",[r("strong",[e._v("NEW FEATURE")])]),e._v(" "),r("ul",[r("li",[e._v("Microsoft DI integration via package Quartz.Extensions.DependencyInjection (also allows bridging to Microsoft Logging)")]),e._v(" "),r("li",[e._v("DI configuration now supports adding scheduler, job and trigger listeners (#877)")]),e._v(" "),r("li",[e._v('DI configuration now processes appsettings.json section "Quartz" looking for key value pairs (#877)')]),e._v(" "),r("li",[e._v("Add diagnostics source and OpenTelemetry support (#901)")]),e._v(" "),r("li",[e._v("Use Microsoft.Data.SqlClient as SQL Server connection library (#839)")]),e._v(" "),r("li",[e._v("ASP.NET Core / Hosting integration and health checks via revisited NuGet package Quartz.AspNetCore (thank you zlzforever for contributing the work)")]),e._v(" "),r("li",[e._v("Introduced a config parameter "),r("code",[e._v("ClusterCheckinMisfireThreshold")]),e._v(" (#692)")]),e._v(" "),r("li",[e._v("Giving meaningful names to examples folders (#701)")]),e._v(" "),r("li",[e._v("Added search patterns/sub directory search to directory scanner job (#411, #708)")]),e._v(" "),r("li",[e._v("Fluent interface for scheduler configuration (#791)")]),e._v(" "),r("li",[e._v("Support every nth week in cron expression (#790)")]),e._v(" "),r("li",[e._v("Enable SQLite job store provider for NetStandard (#802)")]),e._v(" "),r("li",[e._v("Add configurable params for StdRowLockSemaphore for Failure obtaining db row lock")]),e._v(" "),r("li",[e._v("SchedName added to queries as sql parameter (#818)")]),e._v(" "),r("li",[e._v("Server, example and test projects upgraded to user .NET Core 3.1")]),e._v(" "),r("li",[e._v("Nullable reference type annotations have been enabled")]),e._v(" "),r("li",[e._v("Symbols are now provided as a separate NuGet symbol package (snupkg)")]),e._v(" "),r("li",[e._v("SQL Server indexes have been fine-tuned, redundancies were removed and you can follow the current scripts to update to latest version of them")]),e._v(" "),r("li",[e._v("Upgrade MySqlConnector to 1.0 (namespace has changed) (#890)")]),e._v(" "),r("li",[e._v("Support Microsoft.Extensions.Logging.Abstractions (#756)")]),e._v(" "),r("li",[e._v("Support Microsoft.Data.SQLite with full framework (#893)")]),e._v(" "),r("li",[e._v("Support custom calendar JSON serialization (#697)")]),e._v(" "),r("li",[e._v("DI configuration now supports adding scheduler, job and trigger listeners (#877)")]),e._v(" "),r("li",[e._v('DI configuration now processes appsettings.json section "Quartz" looking for key value pairs (#877)')]),e._v(" "),r("li",[e._v("Use Microsoft.Data.SqlClient as SQL Server connection library (#839)")])]),e._v(" "),r("p",[r("strong",[e._v("FIXES")])]),e._v(" "),r("ul",[r("li",[e._v("Allow binary serialization for DirectoryScanJob data (#658)")]),e._v(" "),r("li",[e._v("LibLog - Fixed NLog + Log4net callsite. Added support for NLog structured logging. Optimized Log4net-logger (#705)")]),e._v(" "),r("li",[e._v("Upgrade LibLog to latest version (#749)")]),e._v(" "),r("li",[e._v("RAMJobStore performance improvements (#718, #719, #720)")]),e._v(" "),r("li",[e._v("General performance improvements (#725, #723, #727)")]),e._v(" "),r("li",[e._v("GetTimeBefore() and GetFinalFireTime() should throw NotImplementedException instead of returning null (#731)")]),e._v(" "),r("li",[e._v("Switch to official TimeZoneConverter NuGet package (#739)")]),e._v(" "),r("li",[e._v("Remove invalid TimeSpanParseRule.Days (#782)")]),e._v(" "),r("li",[e._v("Update tables_sqlServer.sql to follow current SQL syntax and structures (#787)")]),e._v(" "),r("li",[e._v("Fix China Standard Time mapping in TimeZoneUtil.cs (#765)")]),e._v(" "),r("li",[e._v("Release BLOCKED triggers in ReleaseAcquiredTrigger (#741 #800)")]),e._v(" "),r("li",[e._v("DailyTimeIntervalTrigger failed to set endingDailyAfterCount = 1")]),e._v(" "),r("li",[e._v("CronTrigger: cover all valid misfire policies, and provide a sensible default and logging when seeing an invalid one")]),e._v(" "),r("li",[e._v("Remove internal dependencies from examples (#742)")]),e._v(" "),r("li",[e._v("Properly assign MaxConcurrency in CreateVolatileScheduler (#726)")]),e._v(" "),r("li",[e._v("Fix potential scheduler deadlock caused by changed lock request id inside ExecuteInNonManagedTXLock (#794)")]),e._v(" "),r("li",[e._v("Ensure NuGet.exe is part of produced zip to ensure build works (#881)")]),e._v(" "),r("li",[e._v("JobDataMap with enum values persisted as JSON can now be set back to job members via PropertySettingJobFactory (#770)")]),e._v(" "),r("li",[e._v("Ensure GetScheduleBuilder for triggers respects IgnoreMisfirePolicy (#750)")]),e._v(" "),r("li",[e._v("Remove cron expression validation from XML schema and rely on CronExpression itself (#729)")])]),e._v(" "),r("Download")],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/55.b96bcec3.js b/assets/js/55.b96bcec3.js new file mode 100644 index 000000000..463682840 --- /dev/null +++ b/assets/js/55.b96bcec3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[55],{429:function(t,a,s){"use strict";s.r(a);var n=s(26),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("This release concentrates on tweaking the DI story and fixing some found dependency issues.")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#quartz-extensions-hosting"}},[t._v("Quartz.Extensions.Hosting")])]),s("li",[s("a",{attrs:{href:"#refining-di-integration-api"}},[t._v("Refining DI integration API")]),s("ul",[s("li",[s("a",{attrs:{href:"#options-pattern"}},[t._v("Options pattern")])]),s("li",[s("a",{attrs:{href:"#schedulejob"}},[t._v("ScheduleJob")])]),s("li",[s("a",{attrs:{href:"#addcalendar"}},[t._v("AddCalendar")])])])]),s("li",[s("a",{attrs:{href:"#microsoft-sql-server"}},[t._v("Microsoft SQL Server")]),s("ul",[s("li",[s("a",{attrs:{href:"#full-framework"}},[t._v("Full Framework")])]),s("li",[s("a",{attrs:{href:"#net-core"}},[t._v(".NET Core")])]),s("li",[s("a",{attrs:{href:"#query-plan-cache-pollution-fix"}},[t._v("Query plan cache pollution fix")])])])]),s("li",[s("a",{attrs:{href:"#github-issues"}},[t._v("GitHub Issues")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"quartz-extensions-hosting"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#quartz-extensions-hosting"}},[t._v("#")]),t._v(" Quartz.Extensions.Hosting")]),t._v(" "),s("p",[t._v("A new package "),s("a",{attrs:{href:"https://www.nuget.org/packages/Quartz.Extensions.Hosting/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Quartz.Extensions.Hosting"),s("OutboundLink")],1),t._v("\nwas created with the help of "),s("a",{attrs:{href:"https://andrewlock.net/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Andrew Lock"),s("OutboundLink")],1),t._v(". If you are using generic host and you don't need\nASP.NET specific functionality like health checks, you can switch to this new package to reduce dependencies.")]),t._v(" "),s("h2",{attrs:{id:"refining-di-integration-api"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#refining-di-integration-api"}},[t._v("#")]),t._v(" Refining DI integration API")]),t._v(" "),s("p",[t._v("Some work was done to improve the MS DI integration API.")]),t._v(" "),s("h3",{attrs:{id:"options-pattern"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#options-pattern"}},[t._v("#")]),t._v(" Options pattern")]),t._v(" "),s("p",[t._v("Now the API uses "),s("a",{attrs:{href:"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options",target:"_blank",rel:"noopener noreferrer"}},[t._v("options pattern"),s("OutboundLink")],1),t._v("\nproperly and you can attach your own configurators to alter "),s("code",[t._v("QuartzOptions")]),t._v(".")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we can use options pattern to support hooking your own configuration")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// because we don't use service registration api")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we need to manally ensure the job is present in DI")]),t._v("\nservices"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTransient")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \nservices"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Configure")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SampleOptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Configuration"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetSection")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sample"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nservices"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddOptions")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("QuartzOptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Configure")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("IOptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("SampleOptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("options"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" dep"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("IsNullOrWhiteSpace")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dep"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CronSchedule"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")])]),t._v(" jobKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options-custom-job"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"custom"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n options"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJob")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n options"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" trigger\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options-custom-trigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"custom"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dep"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CronSchedule"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),s("h3",{attrs:{id:"schedulejob"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#schedulejob"}},[t._v("#")]),t._v(" ScheduleJob")]),t._v(" "),s("p",[t._v("A new shorthand was created to quickly define a job with trigger using a single call.")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v("q"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("ExampleJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" trigger\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Combined Configuration Trigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("EvenSecondDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDailyTimeIntervalSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithInterval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" IntervalUnit"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Second"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome trigger configured for a job with single call"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h3",{attrs:{id:"addcalendar"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#addcalendar"}},[t._v("#")]),t._v(" AddCalendar")]),t._v(" "),s("p",[t._v("You can now add calendars using the DI API.")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" calendarName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidayCalendar"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddCalendar")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HolidayCalendar"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token named-parameter punctuation"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" calendarName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token named-parameter punctuation"}},[t._v("replace")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token named-parameter punctuation"}},[t._v("updateTriggers")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddExcludedDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("DateTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2020")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("t "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" t\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Daily Trigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("EvenSecondDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDailyTimeIntervalSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithInterval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" IntervalUnit"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Second"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithDescription")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"my awesome daily time interval trigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ModifiedByCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("calendarName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h2",{attrs:{id:"microsoft-sql-server"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#microsoft-sql-server"}},[t._v("#")]),t._v(" Microsoft SQL Server")]),t._v(" "),s("p",[t._v("Now Quartz no longer has hard dependency on "),s("code",[t._v("Microsoft.Data.SqlClient")]),t._v(" package.\nFull framework defaults now back to same behavior as it was with Quartz 3.0 (using built-in System.Data.SqlClient driver).")]),t._v(" "),s("h3",{attrs:{id:"full-framework"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#full-framework"}},[t._v("#")]),t._v(" Full Framework")]),t._v(" "),s("p",[t._v("You can use either one of the two providers, "),s("code",[t._v("SqlServer")]),t._v(" (default) or "),s("code",[t._v("SystemDataSqlClient")]),t._v(". Former uses "),s("code",[t._v("System.Data.SqlClient")]),t._v(" and latter\nthe new "),s("a",{attrs:{href:"https://www.nuget.org/packages/Microsoft.Data.SqlClient",target:"_blank",rel:"noopener noreferrer"}},[t._v("Microsoft.Data.SqlClient package"),s("OutboundLink")],1),t._v(".\nIf you choose to use the new package, make sure you have the NuGet package installed.")]),t._v(" "),s("h3",{attrs:{id:"net-core"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#net-core"}},[t._v("#")]),t._v(" .NET Core")]),t._v(" "),s("p",[t._v("You need to ensure you have "),s("a",{attrs:{href:"https://www.nuget.org/packages/Microsoft.Data.SqlClient",target:"_blank",rel:"noopener noreferrer"}},[t._v("Microsoft.Data.SqlClient package"),s("OutboundLink")],1),t._v(" installed.")]),t._v(" "),s("h3",{attrs:{id:"query-plan-cache-pollution-fix"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#query-plan-cache-pollution-fix"}},[t._v("#")]),t._v(" Query plan cache pollution fix")]),t._v(" "),s("p",[t._v("There was an important fix for SQL Server where varying text parameter sizes caused query plan cache pollution. Now when no parameter size is\ndefined for string parameter, default value of 4000 will be used. This problem has been present since the beginning.")]),t._v(" "),s("h2",{attrs:{id:"github-issues"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[t._v("#")]),t._v(" GitHub Issues")]),t._v(" "),s("p",[s("strong",[t._v("BREAKING CHANGES")])]),t._v(" "),s("ul",[s("li",[t._v("Remove dependency on Microsoft.Data.SqlClient (#912)")]),t._v(" "),s("li",[t._v("LogContext moved from Quartz namespace to Quartz.Logging namespace (#915)")]),t._v(" "),s("li",[t._v("For Full Framework, System.Data.SqlClient is again the default provider, Microsoft.Data can be used via provider MicrosoftDataSqlClient (#916)")])]),t._v(" "),s("p",[s("strong",[t._v("NEW FEATURE")])]),t._v(" "),s("ul",[s("li",[t._v("Introduce separate Quartz.Extensions.Hosting (#911)")]),t._v(" "),s("li",[t._v("You can now schedule job and trigger in MS DI integration with single .ScheduleJob call (#943)")]),t._v(" "),s("li",[t._v("Support adding calendars to MS DI via AddCalendar (#945)")])]),t._v(" "),s("p",[s("strong",[t._v("FIXES")])]),t._v(" "),s("ul",[s("li",[t._v("Revert change in 3.1: CronExpression/cron trigger throwing "),s("code",[t._v("NotImplementedException")]),t._v(" when calculating final fire time (#905)")]),t._v(" "),s("li",[t._v("Use 2.1 as the minimum version for the .NET Platform Extensions (#923)")]),t._v(" "),s("li",[t._v("ServiceCollection.AddQuartz() should register default ITypeLoadHelper if none supplied (#924)")]),t._v(" "),s("li",[t._v("SqlServer AdoJobStore SqlParameter without text size generates pressure on server (#939)")]),t._v(" "),s("li",[t._v("DbProvider initialization logic should also read quartz.config (#951)")]),t._v(" "),s("li",[t._v("LoggingJobHistoryPlugin and LoggingTriggerHistoryPlugin names are null with IoC configuration (#926)")]),t._v(" "),s("li",[t._v("Improve options pattern to allow better custom configuration story (#955)")])]),t._v(" "),s("Download")],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/56.6c9b74df.js b/assets/js/56.6c9b74df.js new file mode 100644 index 000000000..70385ae36 --- /dev/null +++ b/assets/js/56.6c9b74df.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[56],{430:function(e,t,o){"use strict";o.r(t);var n=o(26),i=Object(n.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("This is a maintenance release containing mostly bug fixes.")]),e._v(" "),o("p",[e._v("MS dependency injection job factory configuration was unified and you can now configure relevant options\nlike whether to create a separate scope with using just the "),o("code",[e._v("UseMicrosoftDependencyInjectionJobFactory")]),e._v(" and its callback.\nNow scoped jobs also get their properties set from job data map.")]),e._v(" "),o("p",[e._v("Pre-configuring Quartz options from "),o("code",[e._v("appsettings.json")]),e._v(" with "),o("code",[e._v('services.Configure(Configuration.GetSection("Quartz"));')]),e._v("\nnow also works as expected.")]),e._v(" "),o("h2",{attrs:{id:"github-issues"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[e._v("#")]),e._v(" GitHub Issues")]),e._v(" "),o("p",[o("strong",[e._v("FIXES")])]),e._v(" "),o("ul",[o("li",[e._v("Make QuartzOptions Triggers and JobDetails public (#981)")]),e._v(" "),o("li",[e._v("Fix configuration system injection for dictionary/quartz.jobStore.misfireThreshold in DI (#983)")]),e._v(" "),o("li",[e._v("XMLSchedulingDataProcessor can cause IOException due to file locking (#993)")])]),e._v(" "),o("p",[o("strong",[e._v("IMPROVEMENTS")])]),e._v(" "),o("ul",[o("li",[e._v("Unify MS dependency injection job factory logic and configuration (#995)")]),e._v(" "),o("li",[e._v("Improve job dispatch performance to reduce latency before hitting Execute (RAMJobStore) (#996)")])]),e._v(" "),o("Download")],1)}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/57.00f4144b.js b/assets/js/57.00f4144b.js new file mode 100644 index 000000000..1b9f5f17f --- /dev/null +++ b/assets/js/57.00f4144b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[57],{431:function(s,e,t){"use strict";t.r(e);var o=t(26),r=Object(o.a)({},(function(){var s=this,e=s.$createElement,t=s._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("p",[s._v("This release addresses regression in scoped job resolution which was introduced by job factory refactoring done in 3.2.1.")]),s._v(" "),t("h2",{attrs:{id:"github-issues"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[s._v("#")]),s._v(" GitHub Issues")]),s._v(" "),t("p",[t("strong",[s._v("FIXES")])]),s._v(" "),t("ul",[t("li",[s._v("Fix scoped job resolution (#998)")])]),s._v(" "),t("Download")],1)}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/58.816401b6.js b/assets/js/58.816401b6.js new file mode 100644 index 000000000..3210c5452 --- /dev/null +++ b/assets/js/58.816401b6.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[58],{432:function(t,e,a){"use strict";a.r(e);var n=a(26),r=Object(n.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("This release addresses issue with Autofac integration and adds new integration package\n"),a("a",{attrs:{href:"/documentation/quartz-3.x/packages/opentracing-integration"}},[t._v("Quartz.OpenTracing")]),t._v(" to allow\nintegration with OpenTracing contributed by "),a("a",{attrs:{href:"https://github.com/PavelStefanov",target:"_blank",rel:"noopener noreferrer"}},[t._v("Pavel Stefanov"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("h2",{attrs:{id:"github-issues"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[t._v("#")]),t._v(" GitHub Issues")]),t._v(" "),a("p",[a("strong",[t._v("NEW FEATURE")])]),t._v(" "),a("ul",[a("li",[t._v("Add Quartz.OpenTracing support (#1006)")]),t._v(" "),a("li",[t._v("Add UseZeroSizeThreadPool to configuration (#1003)")])]),t._v(" "),a("p",[a("strong",[t._v("FIXES")])]),t._v(" "),a("ul",[a("li",[t._v("Xamarin Android can't get scheduler (#1008)")]),t._v(" "),a("li",[t._v("Autofac job factory registration fails (#1011)")])]),t._v(" "),a("Download")],1)}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/59.39f29e19.js b/assets/js/59.39f29e19.js new file mode 100644 index 000000000..95ee8e1a4 --- /dev/null +++ b/assets/js/59.39f29e19.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[59],{433:function(e,t,i){"use strict";i.r(t);var n=i(26),s=Object(n.a)({},(function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[i("p",[e._v("This release is a maintenance release with couple of bug fixes. The most important fix for this release is that\nnow Quartz distinguishes between external code task cancellation (say "),i("code",[e._v("HttpClient")]),e._v(") and job cancellation triggered by using\nthe Quartz API's "),i("code",[e._v("Interrupt")]),e._v(" method. Earlier Quartz incorrectly considered also other "),i("code",[e._v("OperationCanceledException")]),e._v("s as clean instead of being errors.")]),e._v(" "),i("h2",{attrs:{id:"github-issues"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[e._v("#")]),e._v(" GitHub Issues")]),e._v(" "),i("p",[i("strong",[e._v("FIXES")])]),e._v(" "),i("ul",[i("li",[i("code",[e._v("JobRunShell")]),e._v(" silently handles "),i("code",[e._v("OperationCanceledException")]),e._v(" which is not correct in terms of job retry handling (#1064)")]),e._v(" "),i("li",[e._v("Handled exceptions thrown while retrieving the misfired trigger (#1040)")]),e._v(" "),i("li",[i("code",[e._v("FileScanJob")]),e._v(" is faling after upgrading from 3.0.7 to 3.2.3 (#1027)")]),e._v(" "),i("li",[i("code",[e._v("JobBuilder.UsingJobData(string key, string value)")]),e._v(" should be "),i("code",[e._v("JobBuilder.UsingJobData(string key, string? value)")]),e._v(" (#1025)")])]),e._v(" "),i("Download")],1)}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/6.4b03a90b.js b/assets/js/6.4b03a90b.js new file mode 100644 index 000000000..decd7faa8 --- /dev/null +++ b/assets/js/6.4b03a90b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{343:function(e,t,a){},377:function(e,t,a){"use strict";a(343)},387:function(e,t,a){"use strict";a.r(t);a(49),a(27),a(72),a(73);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(377),a(26)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/assets/js/60.65653623.js b/assets/js/60.65653623.js new file mode 100644 index 000000000..c575b2f84 --- /dev/null +++ b/assets/js/60.65653623.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[60],{434:function(e,o,t){"use strict";t.r(o);var r=t(26),i=Object(r.a)({},(function(){var e=this,o=e.$createElement,t=e._self._c||o;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("This release addresses problems with using Quartz with .NET Full Framework lower than 4.7.2. ValueTask loading\ncould fail due the dependencies brought with activity source support. Now activity sources are only supported when\nusing .NET Framework >= 4.7.2 and netstandard >= 2.0. This also raises requirement the same way for package\nQuartz.OpenTelemetry.Instrumentation.")]),e._v(" "),t("p",[e._v("This release also improves trigger acquisition performance when using persistent job store, mostly by reducing network round-trips.\nThe semaphore implementations were also re-written to gain more performance.")]),e._v(" "),t("p",[e._v("Also some bug fixes included, thanks to all contributors!")]),e._v(" "),t("h2",{attrs:{id:"github-issues"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#github-issues"}},[e._v("#")]),e._v(" GitHub Issues")]),e._v(" "),t("p",[t("strong",[e._v("BREAKING CHANGES")])]),e._v(" "),t("ul",[t("li",[e._v("Activity source listener is not longer part of "),t("code",[e._v("net461")]),e._v(" build, only "),t("code",[e._v("net472")])]),e._v(" "),t("li",[t("code",[e._v("Quartz.AspNetCore")]),e._v(" integration package minimum .NET Core version is now 3.1 for HealthChecks support")])]),e._v(" "),t("p",[t("strong",[e._v("NEW FEATURES")])]),e._v(" "),t("ul",[t("li",[e._v("Separate build configuration for .NET Framework 4.7.2")]),e._v(" "),t("li",[e._v("OpenTelemetry integration upgraded to target OpenTelemetry 1.0.0-rc1.1")]),e._v(" "),t("li",[e._v("Ported "),t("code",[e._v("JobInterruptMonitorPlugin")]),e._v(" from Java version which allows automatic interrupt calls for registered jobs (#1110)")]),e._v(" "),t("li",[e._v("Rewrite semaphore implementations (#1115)")]),e._v(" "),t("li",[t("code",[e._v("UsingJobData")]),e._v(" now has "),t("code",[e._v("Guid")]),e._v(" and "),t("code",[e._v("char")]),e._v(" overloads (#1141)")]),e._v(" "),t("li",[e._v("Add a regular "),t("code",[e._v("AddJob(Type)")]),e._v(" (#1090)")])]),e._v(" "),t("p",[t("strong",[e._v("FIXES")])]),e._v(" "),t("ul",[t("li",[e._v("Jobs not firing after upgrade to 3.2.x (from 3.0.7) on Microsoft Server 2008 R2 (#1083)")]),e._v(" "),t("li",[e._v("Jobs are not fired (#1072)")]),e._v(" "),t("li",[t("code",[e._v("MicrosoftDependencyInjectionJobFactory")]),e._v(" does not inject job properties for scoped jobs (#1106)")]),e._v(" "),t("li",[e._v("XSD schema no longer requires defining "),t("code",[e._v("durable")]),e._v(" element if you just want to define "),t("code",[e._v("recover")]),e._v(" (#1128)")]),e._v(" "),t("li",[e._v("Stack trace logging fixed in case of reporting invalid lock acquire (#1133)")]),e._v(" "),t("li",[e._v("Disposable job is disposed twice when using "),t("code",[e._v("UseMicrosoftDependencyInjectionScopedJobFactory")]),e._v(" (#1120)")]),e._v(" "),t("li",[t("code",[e._v("QuartzHostedService.StopAsync")]),e._v(" throws "),t("code",[e._v("NullReferenceException")]),e._v(" if "),t("code",[e._v("StartAsync")]),e._v(" hasn't been run (#1123)")])]),e._v(" "),t("Download")],1)}),[],!1,null,null,null);o.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/61.7418f9a5.js b/assets/js/61.7418f9a5.js new file mode 100644 index 000000000..9d4908b6f --- /dev/null +++ b/assets/js/61.7418f9a5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[61],{435:function(t,s,e){"use strict";e.r(s);var i=e(26),n=Object(i.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("p",[this._v("This release fixes assembly signing problem introduced in 3.3.")]),this._v(" "),s("p",[s("strong",[this._v("FIXES")])]),this._v(" "),s("ul",[s("li",[this._v("Remove PublicSign property from csproj (#1155)")])]),this._v(" "),s("Download")],1)}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/62.0bc12fc5.js b/assets/js/62.0bc12fc5.js new file mode 100644 index 000000000..2d051b73b --- /dev/null +++ b/assets/js/62.0bc12fc5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[62],{436:function(e,t,o){"use strict";o.r(t);var r=o(26),s=Object(r.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("This release returns the possibility to resolve jobs from Microsoft DI container. Now container is checked first and if not found then\nActivatorUtilities is used to construct the type with constructor injection support. Now both "),o("code",[e._v("AllowDefaultConstructor")]),e._v(" and "),o("code",[e._v("CreateScope")]),e._v(" have\nbeen obsoleted as behavior is now either via DI construction or "),o("code",[e._v("ActivatorUtilities")]),e._v(" and scope is always created to prevent resource leaks / double disposal.")]),e._v(" "),o("p",[e._v("Also a problem with host name resolution under WSL2 scenario was fixed.")]),e._v(" "),o("p",[o("strong",[e._v("FIXES")])]),e._v(" "),o("ul",[o("li",[e._v("Try resolving jobs from service provider before resorting to ActivatorUtilities (#1159)")]),e._v(" "),o("li",[e._v("Can't get hostname on WSL2+docker host network (#1158)")])]),e._v(" "),o("Download")],1)}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/63.a9ad1d02.js b/assets/js/63.a9ad1d02.js new file mode 100644 index 000000000..e40e3dbf6 --- /dev/null +++ b/assets/js/63.a9ad1d02.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[63],{437:function(e,t,o){"use strict";o.r(t);var n=o(26),i=Object(n.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("This is a maintenance release mostly fixing some smaller bugs and improving DI API story.")]),e._v(" "),o("p",[o("strong",[e._v("FIXES")])]),e._v(" "),o("ul",[o("li",[e._v("Lock 'TRIGGER_ACCESS' attempt to return by: de9325af-3e1c-4ae9-a99b-24be994b75f4 -- but not owner! (#1236)")]),e._v(" "),o("li",[e._v("ScheduleJob shorthand: Job name should match trigger name by default (#1211)")]),e._v(" "),o("li",[e._v("CronTriggerImpl.WillFireOn returns wrong result when TimeZone is specified (#1187)")]),e._v(" "),o("li",[e._v("Race condition in DI scheduler listener initialization (#1117)")]),e._v(" "),o("li",[e._v("JobRunShell handle Job CancellationToken (#1183)")]),e._v(" "),o("li",[e._v("Restore System.Data.SqlClient support on .NET Core (#1181)")])]),e._v(" "),o("p",[o("strong",[e._v("IMPROVEMENTS")])]),e._v(" "),o("ul",[o("li",[e._v("Replace static loggers with instance-based (#1264)")]),e._v(" "),o("li",[e._v("Expose more configuration options via programmatic APIs (#1263)")]),e._v(" "),o("li",[e._v("Add ConfigureScope extension point to MicrosoftDependencyInjectionJobFactory (#1189)")]),e._v(" "),o("li",[e._v("Update StdAdoConstants.cs (#1186)")]),e._v(" "),o("li",[e._v("Use custom InstantiateType for all instantiations in StdSchedulerFactory (#1185)")]),e._v(" "),o("li",[e._v("Add support for the ISchedulerFactory.StartDelayed in the QuartzHostedService (#1166)")]),e._v(" "),o("li",[e._v("Remove SimpleThreadPool from examples? (#1230)")])]),e._v(" "),o("Download")],1)}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/64.d0324155.js b/assets/js/64.d0324155.js new file mode 100644 index 000000000..653af5083 --- /dev/null +++ b/assets/js/64.d0324155.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[64],{438:function(t,s,e){"use strict";e.r(s);var n=e(26),l=Object(n.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("h1",{attrs:{id:"blog"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#blog"}},[this._v("#")]),this._v(" Blog")]),this._v(" "),s("BlogIndex")],1)}),[],!1,null,null,null);s.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/65.4e9653df.js b/assets/js/65.4e9653df.js new file mode 100644 index 000000000..3759228e8 --- /dev/null +++ b/assets/js/65.4e9653df.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[65],{439:function(t,a,r){"use strict";r.r(a);var i=r(26),o=Object(i.a)({},(function(){var t=this,a=t.$createElement,r=t._self._c||a;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("ul",[r("li",[r("RouterLink",{attrs:{to:"/documentation/faq.html"}},[t._v("Frequently Asked Questions")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/documentation/best-practices.html"}},[t._v("Best Practices")])],1)]),t._v(" "),r("h2",{attrs:{id:"available-documents-quartz-3-x"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#available-documents-quartz-3-x"}},[t._v("#")]),t._v(" Available Documents (Quartz 3.x):")]),t._v(" "),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-3.x/quick-start.html"}},[t._v("Quick Start Guide")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/index.html"}},[t._v("Tutorials for Developing with Quartz")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-3.x/tutorial/crontrigger.html"}},[t._v("CronTrigger Tutorial")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-3.x/migration-guide.html"}},[t._v("Migration Guide")])],1)]),t._v(" "),r("h2",{attrs:{id:"available-documents-quartz-2-x"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#available-documents-quartz-2-x"}},[t._v("#")]),t._v(" Available Documents (Quartz 2.x):")]),t._v(" "),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-2.x/quick-start.html"}},[t._v("Quick Start Guide")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/index.html"}},[t._v("Tutorials for Developing with Quartz")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/crontrigger.html"}},[t._v("CronTrigger Tutorial")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-2.x/migration-guide.html"}},[t._v("Migration Guide")])],1)]),t._v(" "),r("h2",{attrs:{id:"available-documents-quartz-1-x"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#available-documents-quartz-1-x"}},[t._v("#")]),t._v(" Available Documents (Quartz 1.x):")]),t._v(" "),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/index.html"}},[t._v("Tutorials for Developing with Quartz")])],1)])])}),[],!1,null,null,null);a.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/66.3e14e87f.js b/assets/js/66.3e14e87f.js new file mode 100644 index 000000000..45473fcdb --- /dev/null +++ b/assets/js/66.3e14e87f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[66],{440:function(e,t,a){"use strict";a.r(t);var i=a(26),s=Object(i.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("p",[a("em",[e._v("This document was adapted from Quartz Java")])]),e._v(" "),a("h2",{attrs:{id:"jobdatamap-tips"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobdatamap-tips"}},[e._v("#")]),e._v(" JobDataMap Tips")]),e._v(" "),a("h3",{attrs:{id:"only-store-primitive-data-types-including-strings-in-the-jobdatamap"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#only-store-primitive-data-types-including-strings-in-the-jobdatamap"}},[e._v("#")]),e._v(" Only Store Primitive Data Types (including Strings) In the JobDataMap")]),e._v(" "),a("p",[e._v("Only store primitive data types (including strings) in JobDataMap to avoid data serialization issues short and long-term.")]),e._v(" "),a("h3",{attrs:{id:"use-the-merged-jobdatamap"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#use-the-merged-jobdatamap"}},[e._v("#")]),e._v(" Use the Merged JobDataMap")]),e._v(" "),a("p",[e._v("The JobDataMap that is found on the "),a("code",[e._v("JobExecutionContext")]),e._v(" during Job execution serves as a convenience.\nIt is a merge of the JobDataMap found on the JobDetail and the one found on the Trigger, with the value in the latter overriding any same-named values in the former.")]),e._v(" "),a("p",[e._v("Storing JobDataMap values on a Trigger can be useful in the case where you have a Job that is stored in the scheduler for regular/repeated use by multiple Triggers,\nyet with each independent triggering, you want to supply the Job with different data inputs.")]),e._v(" "),a("p",[e._v("In light of all of the above, we recommend as a best practice the following: Code within the "),a("code",[e._v("IJob.Execute(..)")]),e._v(" method should generally retrieve\nvalues from the JobDataMap on found on the JobExecutionContext, rather than directly from the one on the JobDetail.")]),e._v(" "),a("h2",{attrs:{id:"trigger-tips"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#trigger-tips"}},[e._v("#")]),e._v(" Trigger Tips")]),e._v(" "),a("h3",{attrs:{id:"use-triggerutils"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#use-triggerutils"}},[e._v("#")]),e._v(" Use TriggerUtils")]),e._v(" "),a("p",[e._v("TriggerUtils:")]),e._v(" "),a("ul",[a("li",[e._v("Offers a simple way to create Dates (for start/end dates)")]),e._v(" "),a("li",[e._v("Offers helpers for analyzing triggers (e.g. calculating future fire times)")])]),e._v(" "),a("h2",{attrs:{id:"ado-net-jobstore"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ado-net-jobstore"}},[e._v("#")]),e._v(" ADO.NET JobStore")]),e._v(" "),a("h3",{attrs:{id:"never-write-directly-to-quartz-s-tables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#never-write-directly-to-quartz-s-tables"}},[e._v("#")]),e._v(" Never Write Directly To Quartz's Tables")]),e._v(" "),a("p",[e._v("Writing scheduling data directly to the database (via SQL) rather than using scheduling API:")]),e._v(" "),a("ul",[a("li",[e._v("Results in data corruption (deleted data, scrambled data)")]),e._v(" "),a("li",[e._v('Results in job seemingly "vanishing" without executing when a trigger\'s fire time arrives')]),e._v(" "),a("li",[e._v('Results in job not executing "just sitting there" when a trigger\'s fire time arrives')]),e._v(" "),a("li",[e._v("May result in: Dead-locks")]),e._v(" "),a("li",[e._v("Other strange problems and data corruption")])]),e._v(" "),a("h3",{attrs:{id:"never-point-a-non-clustered-scheduler-at-the-same-database-as-another-scheduler-with-the-same-scheduler-name"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#never-point-a-non-clustered-scheduler-at-the-same-database-as-another-scheduler-with-the-same-scheduler-name"}},[e._v("#")]),e._v(" Never Point A Non-Clustered Scheduler At the Same Database As Another Scheduler With The Same Scheduler Name")]),e._v(" "),a("p",[e._v("If you point more than one scheduler instance at the same set of database tables, and one or more of those instances is not configured for clustering, any of the following may occur:")]),e._v(" "),a("ul",[a("li",[e._v("Results in data corruption (deleted data, scrambled data)")]),e._v(" "),a("li",[e._v('Results in job seemingly "vanishing" without executing when a trigger\'s fire time arrives')]),e._v(" "),a("li",[e._v('Results in job not executing, "just sitting there" when a trigger\'s fire time arrives')]),e._v(" "),a("li",[e._v("May result in: Dead-locks")]),e._v(" "),a("li",[e._v("Other strange problems and data corruption")])]),e._v(" "),a("h3",{attrs:{id:"ensure-adequate-datasource-connection-size"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ensure-adequate-datasource-connection-size"}},[e._v("#")]),e._v(" Ensure Adequate Datasource Connection Size")]),e._v(" "),a("p",[e._v("It is recommended that your Datasource max connection size be configured to be at least the number of worker threads in the thread pool plus three.\nYou may need additional connections if your application is also making frequent calls to the scheduler API.")]),e._v(" "),a("h2",{attrs:{id:"daylight-savings-time"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#daylight-savings-time"}},[e._v("#")]),e._v(" Daylight Savings Time")]),e._v(" "),a("h3",{attrs:{id:"avoid-scheduling-jobs-near-the-transition-hours-of-daylight-savings-time"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#avoid-scheduling-jobs-near-the-transition-hours-of-daylight-savings-time"}},[e._v("#")]),e._v(" Avoid Scheduling Jobs Near the Transition Hours of Daylight Savings Time")]),e._v(" "),a("p",[e._v("NOTE: Specifics of the transition hour and the amount of time the clock moves forward or back varies by locale see: "),a("a",{attrs:{href:"https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world"),a("OutboundLink")],1),e._v(".")]),e._v(" "),a("p",[e._v("SimpleTriggers are not affected by Daylight Savings Time as they always fire at an exact millisecond in time, and repeat an exact number of milliseconds apart.")]),e._v(" "),a("p",[e._v("Because CronTriggers fire at given hours/minutes/seconds, they are subject to some oddities when DST transitions occur.")]),e._v(" "),a("p",[e._v("As an example of possible issues, scheduling in the United States within TimeZones/locations that observe Daylight Savings time, the following problems may occur if using CronTrigger and scheduling fire times during the hours of 1:00 AM and 2:00 AM:")]),e._v(" "),a("ul",[a("li",[e._v("1:05 AM may occur twice! - duplicate firings on CronTrigger possible")]),e._v(" "),a("li",[e._v("2:05 AM may never occur! - missed firings on CronTrigger possible")])]),e._v(" "),a("p",[e._v("Again, specifics of time and amount of adjustment varies by locale.")]),e._v(" "),a("p",[e._v("Other trigger types that are based on sliding along a calendar (rather than exact amounts of time), such as CalenderIntervalTrigger, will be similarly affected - but rather than missing a firing, or firing twice, may end up having it's fire time shifted by an hour.")]),e._v(" "),a("h2",{attrs:{id:"jobs"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobs"}},[e._v("#")]),e._v(" Jobs")]),e._v(" "),a("h3",{attrs:{id:"waiting-for-conditions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#waiting-for-conditions"}},[e._v("#")]),e._v(" Waiting For Conditions")]),e._v(" "),a("p",[e._v("Long-running jobs prevent others from running (if all threads in the ThreadPool are busy).")]),e._v(" "),a("p",[e._v("If you feel the need to call Thread.sleep() on the worker thread executing the Job, it is typically a sign that the job is not ready to do the rest of its work because it needs to wait for some condition (such as the availability of a data record) to become true.")]),e._v(" "),a("p",[e._v("A better solution is to release the worker thread (exit the job) and allow other jobs to execute on that thread. The job can reschedule itself, or other jobs before it exits.")]),e._v(" "),a("h3",{attrs:{id:"throwing-exceptions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#throwing-exceptions"}},[e._v("#")]),e._v(" Throwing Exceptions")]),e._v(" "),a("p",[e._v("A Job's execute method should contain a try-catch block that handles all possible exceptions.")]),e._v(" "),a("p",[e._v("If a job throws an exception, Quartz will typically immediately re-execute it, meaning the job can and likely will throw the same exception again. This can lead to wasted resources and, in the worst cases, unstable or crashed applications.\nIt's better if the job catches all exceptions it may encounter, handles them, and reschedules itself or other jobs to work around the issue.")]),e._v(" "),a("h3",{attrs:{id:"recoverability-and-idempotence"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#recoverability-and-idempotence"}},[e._v("#")]),e._v(" Recoverability and Idempotence")]),e._v(" "),a("p",[e._v('In-progress Jobs marked "recoverable" are automatically re-executed after a scheduler fails. This means some of the job\'s "work" will be executed twice.')]),e._v(" "),a("p",[e._v("This means the job should be coded in such a way that its work is idempotent.")]),e._v(" "),a("h2",{attrs:{id:"listeners-triggerlistener-joblistener-schedulerlistener"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#listeners-triggerlistener-joblistener-schedulerlistener"}},[e._v("#")]),e._v(" Listeners (TriggerListener, JobListener, SchedulerListener)")]),e._v(" "),a("h3",{attrs:{id:"keep-code-in-listeners-concise-and-efficient"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#keep-code-in-listeners-concise-and-efficient"}},[e._v("#")]),e._v(" Keep Code In Listeners Concise And Efficient")]),e._v(" "),a("p",[e._v("Performing large amounts of work is discouraged, as the thread that would be executing the job (or completing the trigger and moving on to firing another job, etc.) will be tied up within the listener.")]),e._v(" "),a("h3",{attrs:{id:"handle-exceptions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#handle-exceptions"}},[e._v("#")]),e._v(" Handle Exceptions")]),e._v(" "),a("p",[e._v("Every listener method should contain a try-catch block that handles all possible exceptions.")]),e._v(" "),a("p",[e._v("If a listener throws an exception, it may cause other listeners not to be notified and/or prevent the execution of the job, etc.")]),e._v(" "),a("h2",{attrs:{id:"exposing-scheduler-functionality-through-applications"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#exposing-scheduler-functionality-through-applications"}},[e._v("#")]),e._v(" Exposing Scheduler Functionality Through Applications")]),e._v(" "),a("h3",{attrs:{id:"be-careful-of-security"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#be-careful-of-security"}},[e._v("#")]),e._v(" Be Careful of Security!")]),e._v(" "),a("p",[e._v("Some users expose Quartz's Scheduler functionality through an application user interface. This can be very useful, though it can also be extremely dangerous.")]),e._v(" "),a("p",[e._v("Be sure you don't mistakenly allow users to define jobs of any type they wish, with whatever parameters they wish.\nFor example, Quartz.Jobs package ships with a pre-made job "),a("code",[e._v("NativeJob")]),e._v(", which will execute any arbitrary native (operating system) system command that it is defined to.\nMalicious users could use this to take control of, or destroy your system.")]),e._v(" "),a("p",[e._v("Likewise other jobs such as "),a("code",[e._v("SendEmailJob")]),e._v(", and virtually any others could be used for malicious intent.")]),e._v(" "),a("p",[e._v("Allowing users to define whatever job they want effectively opens your system to all sorts of vulnerabilities comparable/equivalent to Command Injection Attacks as defined by OWASP and MITRE.")])])}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/67.1aade945.js b/assets/js/67.1aade945.js new file mode 100644 index 000000000..5ab58d9b2 --- /dev/null +++ b/assets/js/67.1aade945.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[67],{441:function(e,t,a){"use strict";a.r(t);var o=a(26),n=Object(o.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),a("p",[e._v("This FAQ was adapted from Quartz Java")])]),e._v(" "),a("h1",{attrs:{id:"general-questions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#general-questions"}},[e._v("#")]),e._v(" General Questions")]),e._v(" "),a("h2",{attrs:{id:"what-is-quartz"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#what-is-quartz"}},[e._v("#")]),e._v(" What is Quartz")]),e._v(" "),a("p",[e._v('Quartz is a job scheduling system that can be integrated with, or used along\nside virtually any other software system. The term "job scheduler" seems to\nconjure different ideas for different people. As you read this tutorial, you\nshould be able to get a firm idea of what we mean when we use this term, but\nin short, a job scheduler is a system that is responsible for executing\n(or notifying) other software components when a pre-determined (scheduled)\ntime arrives.')]),e._v(" "),a("p",[e._v("Quartz is quite flexible, and contains multiple usage paradigms that can be\nused separately or together, in order to achieve your desired behavior, and\nenable you to write your code in the manner that seems most 'natural' to\nyour project.")]),e._v(" "),a("p",[e._v("Quartz is very light-weight, and requires very little setup/configuration -\nit can actually be used 'out-of-the-box' if your needs are relatively basic.")]),e._v(" "),a("p",[e._v("Quartz is fault-tolerant, and can persist ('remember') your scheduled\njobs between system restarts.")]),e._v(" "),a("p",[e._v("Although Quartz is extremely useful for simply running certain system\nprocesses on given schedules, the full potential of Quartz can be realized\nwhen you learn how to use it to drive the flow of your application's\nbusiness processes.")]),e._v(" "),a("h2",{attrs:{id:"what-is-quartz-from-a-software-component-view"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#what-is-quartz-from-a-software-component-view"}},[e._v("#")]),e._v(" What is Quartz - From a Software Component View?")]),e._v(" "),a("p",[e._v("Quartz is distributed as a small dynamically linked library (.dll file)\nthat contains all of the core Quartz functionality. The main interface (API) to this\nfunctionality is the Scheduler interface. It provides simple operations\nsuch as scheduling/unscheduling jobs, starting/stopping/pausing the scheduler.")]),e._v(" "),a("p",[e._v("If you wish to schedule your own software components for execution they must\nimplement the simple Job interface, which contains the method execute().\nIf you wish to have components notified when a scheduled fire-time arrives,\nthen the components should implement either the TriggerListener or JobListener\ninterface.")]),e._v(" "),a("p",[e._v("The main Quartz 'process' can be started and ran within your own application,\nor a stand-alone application (with an remote interface).")]),e._v(" "),a("h1",{attrs:{id:"why-not-just-use-system-timers-timer"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#why-not-just-use-system-timers-timer"}},[e._v("#")]),e._v(" Why not just use System.Timers.Timer?")]),e._v(" "),a("p",[e._v('.NET Framework has "built-in" timer capabilities, through the\nSystem.Timers.Timer class - why would someone use Quartz rather than these\nstandard features?')]),e._v(" "),a("p",[e._v("There are many reasons! Here are a few:")]),e._v(" "),a("ul",[a("li",[e._v("Timers have no persistence mechanism.")]),e._v(" "),a("li",[e._v("Timers have inflexible scheduling (only able to set start-time & repeat interval, nothing based on dates, time of day, etc.")]),e._v(" "),a("li",[e._v("Timers don't utilize a thread-pool (one thread per timer)")]),e._v(" "),a("li",[e._v("Timers have no real management schemes - you'd have to write your own mechanism for being able to remember, organize and retreive your tasks by name, etc.")])]),e._v(" "),a("p",[e._v("...of course to some simple applications these features may not be important,\nin which case it may then be the right decision not to use Quartz.NET.")]),e._v(" "),a("h1",{attrs:{id:"miscellaneous-questions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#miscellaneous-questions"}},[e._v("#")]),e._v(" Miscellaneous Questions")]),e._v(" "),a("h2",{attrs:{id:"how-many-jobs-is-quartz-capable-of-running"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-many-jobs-is-quartz-capable-of-running"}},[e._v("#")]),e._v(" How many jobs is Quartz capable of running?")]),e._v(" "),a("p",[e._v('This is a tough question to answer... the answer is basically "it depends".')]),e._v(" "),a("p",[e._v('I know you hate that answer, to here\'s some information about what it depends "on".')]),e._v(" "),a("p",[e._v('First off, the JobStore that you use plays a significant factor.\nThe RAM-based JobStore is MUCH (1000x) faster than the ADO.NET-based JobStore.\nThe speed of AdoJobStore depends almost entirely on the speed of the\nconnection to your database, which data base system that you use, and what\nhardware the database is running on. Quartz actually does very little\nprocessing itself, nearly all of the time is spent in the database. Of course\nRAMJobStore has a more finite limit on how many Jobs & Triggers can be stored,\nas you\'re sure to have less RAM than hard-drive space for a database.\nYou may also look at the FAQ "How do I improve the performance of AdoJobStore?"')]),e._v(" "),a("p",[e._v('So, the limitting factor of the number of Triggers and Jobs Quartz can "store"\nand monitor is really the amount of storage space available to the JobStore\n(either the amount of RAM or the amount of disk space).')]),e._v(" "),a("p",[e._v('Now, aside from "how many can I store?" is the question of "how many jobs\ncan Quartz be running at the same moment in time?"')]),e._v(" "),a("p",[e._v('One thing that CAN slow down quartz itself is using a lot of listeners\n(TriggerListeners, JobListeners, and SchedulerListeners). The time spent in\neach listener obviously adds into the time spent "processing" a job\'s\nexecution, outside of actual execution of the job. This doesn\'t mean that\nyou should be terrified of using listeners, it just means that you should\nuse them judiciously - don\'t create a bunch of "global" listeners if you can\nreally make more specialized ones. Also don\'t do "expensive" things in the\nlisteners, unless you really need to. Also be mindful that many\nplug-ins (such as the "history" plugin) are actually listeners.')]),e._v(" "),a("p",[e._v("The actual number of jobs that can be running at any moment in time is\nlimitted by the size of the thread pool. If there are five threads in\nthe pool, no more than five jobs can run at a time. Be careful of making a\nlot of threads though, as the VM, Operating System, and CPU all have a hard\ntime juggling lots of threads, and performance degrades just because of all\nof the management. In most cases performance starts to tank as you get into\nthe hundreds of threads. Be mindful that if you're running within an\napplication server, it probably has created at least a few dozen threads\nof its own!")]),e._v(" "),a("p",[e._v("Aside from those factors, it really comes down to what your jobs DO.\nIf your jobs take a long time to complete their work, and/or their work is\nvery CPU-intensive, then you're obviously not going to be able to run very\nmany jobs at once, nor very many in a given spanse of time.")]),e._v(" "),a("p",[e._v("Finally, if you just can't get enough horse-power out of one Quartz instance,\nyou can always load-balance many Quartz instances (on separate machines).\nEach will run the jobs out of the shared database on a first-come first-serve\nbasis, as quickly as the triggers need fired.")]),e._v(" "),a("p",[e._v('So here you are this far into the answer of "how many", and I still\nhaven\'t given you a number And I really hate to, because of all of the\nvariables mentioned above. So let me just say, there are installments of\nQuartz Java out there that are managing hundreds-of-thousands of Jobs and Triggers,\nand that at any given moment in time are executing dozens of jobs - and this\nexcludes using load-balancing. With this in mind, most people should feel\nconfident that they can get the performance out of Quartz that they need.')]),e._v(" "),a("h1",{attrs:{id:"questions-about-jobs"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#questions-about-jobs"}},[e._v("#")]),e._v(" Questions About Jobs")]),e._v(" "),a("h2",{attrs:{id:"how-can-i-control-the-instantiation-of-jobs"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-can-i-control-the-instantiation-of-jobs"}},[e._v("#")]),e._v(" How can I control the instantiation of Jobs?")]),e._v(" "),a("p",[e._v("See Quartz.Spi.IJobFactory and the Quartz.IScheduler.JobFactory property.")]),e._v(" "),a("h2",{attrs:{id:"how-do-i-keep-a-job-from-being-removed-after-it-completes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-do-i-keep-a-job-from-being-removed-after-it-completes"}},[e._v("#")]),e._v(" How do I keep a Job from being removed after it completes?")]),e._v(" "),a("p",[e._v('Set the property JobDetail.Durable = true - which instructs Quartz not to\ndelete the Job when it becomes an "orphan" (when the Job not longer has a\nTrigger referencing it).')]),e._v(" "),a("h2",{attrs:{id:"how-do-i-keep-a-job-from-firing-concurrently"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-do-i-keep-a-job-from-firing-concurrently"}},[e._v("#")]),e._v(" How do I keep a Job from firing concurrently?")]),e._v(" "),a("p",[a("strong",[e._v("Quartz.NET 2.x")])]),e._v(" "),a("p",[e._v("Implement "),a("strong",[e._v("IJob")]),e._v(" and also decorate your job class with "),a("code",[e._v("[DisallowConcurrentExecution]")]),e._v(" attribute. Read the API\ndocumentation for "),a("code",[e._v("DisallowConcurrentExecutionAttribute")]),e._v(" for more information.")]),e._v(" "),a("p",[a("strong",[e._v("Quartz.NET 1.x")])]),e._v(" "),a("p",[e._v("Make the job class implement "),a("code",[e._v("IStatefulJob")]),e._v(" rather than "),a("code",[e._v("IJob")]),e._v(". Read the API\ndocumentation for "),a("code",[e._v("IStatefulJob")]),e._v(" for more information.")]),e._v(" "),a("h2",{attrs:{id:"how-do-i-stop-a-job-that-is-currently-executing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-do-i-stop-a-job-that-is-currently-executing"}},[e._v("#")]),e._v(" How do I stop a Job that is currently executing?")]),e._v(" "),a("p",[e._v("Quartz 1.x and 2x: See the "),a("code",[e._v("Quartz.IInterruptableJob")]),e._v(" interface, and the "),a("code",[e._v("IScheduler.Interrupt(string, string)")]),e._v(" method.")]),e._v(" "),a("p",[e._v("Quartz 3.x: See "),a("code",[e._v("IJobExecutionContext")]),e._v("'s "),a("code",[e._v("CancellationToken.IsCancellationRequested")])]),e._v(" "),a("h1",{attrs:{id:"questions-about-triggers"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#questions-about-triggers"}},[e._v("#")]),e._v(" Questions About Triggers")]),e._v(" "),a("h2",{attrs:{id:"how-do-i-chain-job-execution-or-how-do-i-create-a-workflow"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-do-i-chain-job-execution-or-how-do-i-create-a-workflow"}},[e._v("#")]),e._v(" How do I chain Job execution? Or, how do I create a workflow?")]),e._v(" "),a("p",[e._v('There currently is no "direct" or "free" way to chain triggers with Quartz.\nHowever there are several ways you can accomplish it without much effort.\nBelow is an outline of a couple approaches:')]),e._v(" "),a("p",[e._v("One way is to use a listener (i.e. a TriggerListener, JobListener or\nSchedulerListener) that can notice the completion of a job/trigger and then\nimmediately schedule a new trigger to fire. This approach can get a bit\ninvolved, since you'll have to inform the listener which job follows which")]),e._v(" "),a("ul",[a("li",[e._v("and you may need to worry about persistence of this information.")])]),e._v(" "),a("p",[e._v("Another way is to build a Job that contains within its JobDataMap the name\nof the next job to fire, and as the job completes (the last step in its\n"),a("code",[e._v("Execute()")]),e._v(" method) have the job schedule the next job. Several people are\ndoing this and have had good luck. Most have made a base (abstract) class\nthat is a Job that knows how to get the job name and group out of the\nJobDataMap using special keys (constants) and contains code to schedule the\nidentified job. Then they simply make extensions of this class that included\nthe additional work the job should do.")]),e._v(" "),a("p",[e._v("In the future, Quartz will provide a much cleaner way to do this, but until\nthen, you'll have to use one of the above approaches, or think of yet another\nthat works better for you.")]),e._v(" "),a("h2",{attrs:{id:"why-isn-t-my-trigger-firing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#why-isn-t-my-trigger-firing"}},[e._v("#")]),e._v(" Why isn't my trigger firing?")]),e._v(" "),a("p",[e._v("The most common reason for this is not having called "),a("code",[e._v("Scheduler.Start()")]),e._v(",\nwhich tells the scheduler to start firing triggers.")]),e._v(" "),a("p",[e._v("The second most common reason is that the trigger or trigger group\nhas been paused.")]),e._v(" "),a("h2",{attrs:{id:"daylight-saving-time-and-triggers"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#daylight-saving-time-and-triggers"}},[e._v("#")]),e._v(" Daylight Saving Time and Triggers")]),e._v(" "),a("p",[e._v("CronTrigger and SimpleTrigger each handle daylight savings time in their own\nway - each in the way that is intuitive to the trigger type.")]),e._v(" "),a("p",[e._v("First, as a review of what daylight savings time is, please read this resource:\nhttp://webexhibits.org/daylightsaving/g.html . Some readers may be unaware\nthat the rules are different for different nations/contents. For example,\nthe 2005 daylight savings time starts in the United States on April 3, but\nin Egypt on April 29. It is also important to know that not only the dates\nare different for different locals, but the time of the shift is different\nas well. Many places shift at 2:00 am, but others shift time at 1:00 am,\nothers at 3:00 am, and still others right at midnight.")]),e._v(" "),a("p",[e._v('SimpleTrigger allows you to schedule jobs to fire every N milliseconds.\nAs such, it has to do nothing in particular with respect to daylight\nsavings time in order to "stay on schedule" - it simply keeps firing every\nN milliseconds. Regardless your SimpleTrigger is firing every 10 seconds,\nor every 15 minutes, or every hour or every 24 hours it will continue to do\nso. However the implication of this which confuses some users is that if\nyour SimpleTrigger is firing say every 12 hours, before daylight savings\nswitches it may be firing at what appears to be 3:00 am and 3:00 pm,\nbut after daylight savings 4:00 am and 4:00 pm. This is not a bug')]),e._v(" "),a("ul",[a("li",[e._v('the trigger has kept firing exacly every N milliseconds, it just that the\n"name" of that time that humans impose on that moment has changed.')])]),e._v(" "),a("p",[e._v('CronTrigger allows you to schedule jobs to fire at certain moments with\nrespect to a "gregorian calendar". Hence, if you create a trigger to fire\nevery day at 10:00 am, before and after daylight savings time switches it\nwill continue to do so. However, depending on whether it was the Spring or\nAutumn daylight savings event, for that particular Sunday, the actual time\ninterval between the firing of the trigger on Sundary morning at 10:00 am\nsince its firing on Saturday morning at 10:00 am will not be 24 hours,\nbut will instead be 23 or 25 hours respectively.')]),e._v(" "),a("p",[e._v("There is one additional point users must understand about CronTrigger with\nrespect to daylight savings. This is that you should take careful thought\nabout creating schedules that fire between midnight and 3:00 am (the critical\nwindow of time depends on your trigger's locale, as explained above).\nThe reason is that depending on your trigger's schedule, and the particular\ndaylight event, the trigger may be skipped or may appear to not fire for an\nhour or two. As examples, say you are in the United States, where daylight\nsavings events occur at 2:00 am. If you have a CronTrrigger that fires every\nday at 2:15 am, then on the day of the beginning of daylight savings time\nthe trigger will be skipped, since, 2:15 am never occurs that day. If you\nhave a CronTrigger that fires every 15 minutes of every hour of every day,\nthen on the day daylight savings time ends you will have an hour of time\nfor which no triggerings occur, because when 2:00 am arrives, it will become\n1:00 am again, however all of the firings during the one o'clock hour have\nalready occurred, and the trigger's next fire time was set to 2:00 am")]),e._v(" "),a("ul",[a("li",[e._v("hence for the next hour no triggerings will occur.")])]),e._v(" "),a("p",[e._v("In summary, all of this makes perfect sense, and should be easy to remember\nif you keep these two rules in mind:")]),e._v(" "),a("ul",[a("li",[e._v("SimpleTrigger ALWAYS fires exacly every N seconds, with no relation to the time of day.")]),e._v(" "),a("li",[e._v("CronTrigger ALWAYS fires at a given time of day and then computes its next time to fire. If that time does not occur on a given day, the trigger will be skipped. If the time occurs twice in a given day, it only fires once, because after firing on that time the first time, it computes the next time of day to fire on.")])]),e._v(" "),a("h1",{attrs:{id:"questions-about-adojobstore"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#questions-about-adojobstore"}},[e._v("#")]),e._v(" Questions About AdoJobStore")]),e._v(" "),a("h2",{attrs:{id:"how-do-i-improve-the-performance-of-adojobstore"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-do-i-improve-the-performance-of-adojobstore"}},[e._v("#")]),e._v(" How do I improve the performance of AdoJobStore?")]),e._v(" "),a("p",[e._v("There are a few known ways to speed up AdoJobStore, only one of which is\nvery practical.")]),e._v(" "),a("p",[e._v("First, the obvious, but not-so-practical:")]),e._v(" "),a("ul",[a("li",[e._v("Buy a better (faster) network between the machine that runs Quartz, and the machine that runs your RDBMS.")]),e._v(" "),a("li",[e._v("Buy a better (more powerful) machine to run your database on.")]),e._v(" "),a("li",[e._v("Buy a better RDBMS.")])]),e._v(" "),a("p",[e._v("Secondly, use driver delegate implementation that is specific to your database, like "),a("code",[e._v("SQLServerDelegate")]),e._v(", for best performance.")]),e._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[e._v("TIP")]),e._v(" "),a("p",[e._v("You should also always prefer the latest version of the library. Quartz.NET 2.0 is much more efficient than 1.x series and 2.2.x line again has AdoJobStore related performance improvements over earlier 2.x releases.")])]),e._v(" "),a("h1",{attrs:{id:"quartz-in-web-environment"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#quartz-in-web-environment"}},[e._v("#")]),e._v(" Quartz in web environment")]),e._v(" "),a("h2",{attrs:{id:"scheduler-keeps-stopping-when-application-pool-gets-recycled"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#scheduler-keeps-stopping-when-application-pool-gets-recycled"}},[e._v("#")]),e._v(" Scheduler keeps stopping when application pool gets recycled")]),e._v(" "),a("p",[e._v("By default IIS recycles and stops app pools from time to time. This means that even if you have Application_Start event to start Quartz when web app is being first accessed, the scheduler might get disposed later on due to site inactivity.")]),e._v(" "),a("p",[e._v("If you have a IIS 8 available, you can configure your site to be preloaded and kept running. See "),a("a",{attrs:{href:"https://blogs.msdn.microsoft.com/vijaysk/2012/10/11/iis-8-whats-new-website-settings/",target:"_blank",rel:"noopener noreferrer"}},[e._v("this blog post"),a("OutboundLink")],1),e._v(" for details.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/68.ada97766.js b/assets/js/68.ada97766.js new file mode 100644 index 000000000..339226e31 --- /dev/null +++ b/assets/js/68.ada97766.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[68],{442:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/69.3918d066.js b/assets/js/69.3918d066.js new file mode 100644 index 000000000..5433ca461 --- /dev/null +++ b/assets/js/69.3918d066.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[69],{443:function(t,o,e){"use strict";e.r(o);var r=e(26),s=Object(r.a)({},(function(){var t=this,o=t.$createElement,e=t._self._c||o;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h2",{attrs:{id:"choose-a-lesson"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#choose-a-lesson"}},[t._v("#")]),t._v(" Choose a lesson:")]),t._v(" "),e("ul",[e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/using-quartz.html"}},[t._v("Lesson 1: Using Quartz")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/jobs-and-triggers.html"}},[t._v("Lesson 2: Jobs And Triggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/more-about-jobs.html"}},[t._v("Lesson 3: More About Jobs & JobDetails")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/more-about-triggers.html"}},[t._v("Lesson 4: More About Triggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/simpletriggers.html"}},[t._v("Lesson 5: SimpleTriggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/crontriggers.html"}},[t._v("Lesson 6: CronTriggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/trigger-and-job-listeners.html"}},[t._v("Lesson 7: TriggerListeners & JobListeners")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/scheduler-listeners.html"}},[t._v("Lesson 8: SchedulerListeners")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/job-stores.html"}},[t._v("Lesson 9: JobStores")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/configuration-resource-usage-and-scheduler-factory.html"}},[t._v("Lesson 10: Configuration, Resource Usage and SchedulerFactory")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/advanced-enterprise-features.html"}},[t._v("Lesson 11: Advanced (Enterprise) Features")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/miscellaneous-features.html"}},[t._v("Lesson 12: Miscellaneous Features")])],1)])])}),[],!1,null,null,null);o.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/7.73b42248.js b/assets/js/7.73b42248.js new file mode 100644 index 000000000..31177445a --- /dev/null +++ b/assets/js/7.73b42248.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{521:function(t,s,i){"use strict";i.r(s);var n=i(26),e=Object(n.a)({},(function(){var t=this.$createElement;this._self._c;return this._m(0)}),[function(){var t=this.$createElement,s=this._self._c||t;return s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[this._v("\n Version compatibility\n ")]),this._v(" "),s("p",[this._v("\n This documentation relates to Quartz version 3.0 and later.\n ")])])}],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/70.6d54ab0b.js b/assets/js/70.6d54ab0b.js new file mode 100644 index 000000000..c647d7648 --- /dev/null +++ b/assets/js/70.6d54ab0b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[70],{444:function(e,t,r){"use strict";r.r(t);var n=r(26),i=Object(n.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h2",{attrs:{id:"clustering"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#clustering"}},[e._v("#")]),e._v(" Clustering")]),e._v(" "),r("p",[e._v('Clustering currently only works with the AdoJobstore (JobStoreTX). Features include load-balancing and job fail-over (if the JobDetail\'s "request recovery" flag is set to true).')]),e._v(" "),r("p",[e._v('Enable clustering by setting the "quartz.jobStore.clustered" property to "true".\nEach instance in the cluster should use the same copy of the quartz properties.\nExceptions of this would be to use properties that are identical, with the following allowable exceptions:\nDifferent thread pool size, and different value for the "quartz.scheduler.instanceId" property.\nEach node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing "AUTO" as the value of this property.')]),e._v(" "),r("p",[e._v("Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly\n(the clocks must be within a second of each other). See "),r("a",{attrs:{href:"http://www.boulder.nist.gov/timefreq/service/its.htm"}},[e._v("http://www.boulder.nist.gov/timefreq/service/its.htm")]),e._v("\nif you are unfamiliar with how to do this.")]),e._v(" "),r("p",[e._v("Never fire-up a non-clustered instance against the same set of tables that any other instance is running against.\nYou may get serious data corruption, and will definitely experience eratic behavior.")])])}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/71.a7334470.js b/assets/js/71.a7334470.js new file mode 100644 index 000000000..e538f7e93 --- /dev/null +++ b/assets/js/71.a7334470.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[71],{445:function(e,t,o){"use strict";o.r(t);var r=o(26),n=Object(r.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v('Quartz is architected in modular way, and therefore to get it running, several components need to be "snapped" together.\nFortunately, some helpers exist for making this happen.')]),e._v(" "),o("p",[e._v("The major components that need to be configured before Quartz can do its work are:")]),e._v(" "),o("ul",[o("li",[e._v("ThreadPool")]),e._v(" "),o("li",[e._v("JobStore")]),e._v(" "),o("li",[e._v("DataSources (if necessary)")]),e._v(" "),o("li",[e._v("The Scheduler itself")])]),e._v(" "),o("p",[e._v("The ThreadPool provides a set of Threads for Quartz to use when executing Jobs.\nThe more threads in the pool, the greater number of Jobs that can run concurrently.\nHowever, too many threads may bog-down your system.\nMost Quartz users find that 5 or so threads are plenty- because they have fewer than 100 jobs at any given time,\nthe jobs are not generally scheduled to run at the same time, and the jobs are short-lived (complete quickly).\nOther users find that they need 10, 15, 50 or even 100 threads - because they have tens-of-thousands\nof triggers with various schedules - which end up having an average of between 10 and 100 jobs trying to\nexecute at any given moment. Finding the right size for your scheduler's pool is completely dependent on\nwhat you're using the scheduler for. There are no real rules, other than to keep the number of threads as\nsmall as possible (for the sake of your machine's resources) - but make sure you have enough for your Jobs to fire on time.\nNote that if a trigger's time to fire arrives, and there isn't an available thread,\nQuartz will block (pause) until a thread comes available, then the Job will execute -\nsome number of milliseconds later than it should have. This may even cause the tread to misfire - if\nthere is no available thread for the duration of the scheduler's configured \"misfire threshold\".")]),e._v(" "),o("p",[e._v("A IThreadPool interface is defined in the Quartz.Spi namespace, and you can create a IThreadPool implementation in any way you like.\nQuartz ships with a simple (but very satisfactory) thread pool named Quartz.Simpl.SimpleThreadPool.\nThis IThreadPool implementation simply maintains a fixed set of threads in its pool - never grows, never shrinks.\nBut it is otherwise quite robust and is very well tested - as nearly everyone using Quartz uses this pool.")]),e._v(" "),o("p",[e._v("JobStores and DataSrouces were discussed in Lesson 9 of this tutorial. Worth noting here, is the fact that all JobStores\nimplement the IJobStore interface - and that if one of the bundled JobStores does not fit your needs, then you can make your own.")]),e._v(" "),o("p",[e._v("Finally, you need to create your Scheduler instance. The Scheduler itself needs to be given a name and handed\ninstances of a JobStore and ThreadPool.")]),e._v(" "),o("h2",{attrs:{id:"stdschedulerfactory"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#stdschedulerfactory"}},[e._v("#")]),e._v(" StdSchedulerFactory")]),e._v(" "),o("p",[e._v("StdSchedulerFactory is an implementation of the ISchedulerFactory interface.\nIt uses a set of properties (NameValueCollection) to create and initialize a Quartz Scheduler.\nThe properties are generally stored in and loaded from a file, but can also be created by your program and handed directly to the factory.\nSimply calling getScheduler() on the factory will produce the scheduler, initialize it (and its ThreadPool, JobStore and DataSources),\nand return a handle to its public interface.")]),e._v(" "),o("p",[e._v('There are some sample configurations (including descriptions of the properties) in the "docs/config" directory of the Quartz distribution.\nYou can find complete documentation in the "Configuration" manual under the "Reference" section of the Quartz documentation.')]),e._v(" "),o("h2",{attrs:{id:"directschedulerfactory"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#directschedulerfactory"}},[e._v("#")]),e._v(" DirectSchedulerFactory")]),e._v(" "),o("p",[e._v("DirectSchedulerFactory is another SchedulerFactory implementation. It is useful to those wishing to create their Scheduler\ninstance in a more programatic way. Its use is generally discouraged for the following reasons: (1) it\nrequires the user to have a greater understanding of what they're doing, and (2) it does not allow for declaritive\nconfiguration - or in other words, you end up hard-coding all of the scheduler's settings.")]),e._v(" "),o("h2",{attrs:{id:"logging"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#logging"}},[e._v("#")]),e._v(" Logging")]),e._v(" "),o("p",[e._v("Quartz.NET uses the "),o("a",{attrs:{href:"http://netcommon.sourceforge.net/"}},[e._v("Common.Logging framework")]),e._v(' for all of its logging needs.\nQuartz does not produce much logging information - generally just some information during initialization, and\nthen only messages about serious problems while Jobs are executing. In order to "tune" the logging settings\n(such as the amount of output, and where the output goes), you need to understand the Commmon.Logging framework,\nwhich is beyond the scope of this document, please refer to '),o("a",{attrs:{href:"http://netcommon.sourceforge.net/documentation.html"}},[e._v("Common.Logging Documentation")]),e._v(".")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/72.337891b4.js b/assets/js/72.337891b4.js new file mode 100644 index 000000000..6074f6b0a --- /dev/null +++ b/assets/js/72.337891b4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[72],{446:function(e,t,s){"use strict";s.r(t);var n=s(26),a=Object(n.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("p",[e._v("CronTriggers are often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions,\nrather than on the exactly specified intervals of SimpleTrigger.")]),e._v(" "),s("p",[e._v('With CronTrigger, you can specify firing-schedules such as "every Friday at noon", or "every weekday and 9:30 am",\nor even "every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday".')]),e._v(" "),s("p",[e._v("Even so, like SimpleTrigger, CronTrigger has a startTime which specifies when the schedule is in force, and an (optional)\nendTime that specifies when the schedule should be discontinued.")]),e._v(" "),s("h3",{attrs:{id:"cron-expressions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cron-expressions"}},[e._v("#")]),e._v(" Cron Expressions")]),e._v(" "),s("p",[e._v("Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up\nof seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:")]),e._v(" "),s("ul",[s("li",[s("ol",[s("li",[e._v("Seconds")])])]),e._v(" "),s("li",[s("ol",{attrs:{start:"2"}},[s("li",[e._v("Minutes")])])]),e._v(" "),s("li",[s("ol",{attrs:{start:"3"}},[s("li",[e._v("Hours")])])]),e._v(" "),s("li",[s("ol",{attrs:{start:"4"}},[s("li",[e._v("Day-of-Month")])])]),e._v(" "),s("li",[s("ol",{attrs:{start:"5"}},[s("li",[e._v("Month")])])]),e._v(" "),s("li",[s("ol",{attrs:{start:"6"}},[s("li",[e._v("Day-of-Week")])])]),e._v(" "),s("li",[s("ol",{attrs:{start:"7"}},[s("li",[e._v("Year (optional field)")])])])]),e._v(" "),s("p",[e._v('An example of a complete cron-expression is the string "0 0 12 ? * WED" - which means "every Wednesday at 12:00 pm".')]),e._v(" "),s("p",[e._v('Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED")\nexample could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".')]),e._v(" "),s("p",[e._v("Wild-cards (the '"),s("em",[e._v("' character) can be used to say \"every\" possible value of this field. Therefore the '")]),e._v('\' character in the\n"Month" field of the previous example simply means "every month". A \'*\' in the Day-Of-Week field would obviously mean "every day of the week".')]),e._v(" "),s("p",[e._v("All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers\n0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful\nabout how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings\nJAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday)\nor by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.")]),e._v(" "),s("p",[e._v("The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes,\nstarting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour,\nstarting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.")]),e._v(" "),s("p",[e._v("The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify \"no specific value\".\nThis is useful when you need to specify something in one of the two fields, but not the other.\nSee the examples below (and CronTrigger API documentation) for clarification.")]),e._v(" "),s("p",[e._v('The \'L\' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last",\nbut it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means\n"the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself,\nit simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" -\nfor example "6L" or "FRIL" both mean "the last friday of the month". When using the \'L\' option, it is important not to specify lists,\nor ranges of values, as you\'ll get confusing results.')]),e._v(" "),s("p",[e._v('The \'W\' is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month".')]),e._v(" "),s("p",[e._v('The \'#\' is used to specify "the nth" XXX weekday of the month. For example, the value of "6#3" or "FRI#3" in the day-of-week field means "the third Friday of the month".')]),e._v(" "),s("h2",{attrs:{id:"example-cron-expressions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#example-cron-expressions"}},[e._v("#")]),e._v(" Example Cron Expressions")]),e._v(" "),s("p",[e._v("Here are a few more examples of expressions and their meanings - you can find even more in the API documentation for CronTrigger")]),e._v(" "),s("p",[s("strong",[e._v("CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes")])]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[e._v('"0 0/5 * * * ?"\n')])])]),s("p",[s("strong",[e._v("CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).")])]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[e._v('"10 0/5 * * * ?"\n')])])]),s("p",[s("strong",[e._v("CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.")])]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[e._v('"0 30 10-13 ? * WED,FRI"\n')])])]),s("p",[s("strong",[e._v("CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month.\nNote that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30")])]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[e._v('"0 0/30 8-9 5,20 * ?"\n')])])]),s("p",[e._v('Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am,\nand every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.')]),e._v(" "),s("h3",{attrs:{id:"crontrigger-misfire-instructions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#crontrigger-misfire-instructions"}},[e._v("#")]),e._v(" CronTrigger Misfire Instructions")]),e._v(" "),s("p",[e._v("The following instructions can be used to inform Quartz what it should do when a misfire occurs for CronTrigger.\n(Misfire situations were introduced in the More About Triggers section of this tutorial). These instructions are defined in MisfireInstruction.CronTrigger as\nconstants (and API documentation has description for their behavior). The instructions include:")]),e._v(" "),s("ul",[s("li",[e._v("DoNothing")]),e._v(" "),s("li",[e._v("FireOnceNow")])]),e._v(" "),s("p",[e._v("All triggers have the MisfireInstrution.SmartPolicy instruction available for use, and this instruction is also the default for all trigger types.\nThe 'smart policy' instruction is interpreted by CronTrigger as MisfireInstruction.CronTrigger.FireOnceNow. The API documentation for the\nCronTrigger.UpdateAfterMisfire() method explains the exact details of this behavior.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/73.6f58b4eb.js b/assets/js/73.6f58b4eb.js new file mode 100644 index 000000000..70b0db511 --- /dev/null +++ b/assets/js/73.6f58b4eb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[73],{447:function(e,t,o){"use strict";o.r(t);var a=o(26),r=Object(a.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("JobStore's are responsible for keeping track of all the \"work data\" that you give to the scheduler:\njobs, triggers, calendars, etc. Selecting the appropriate IJobStore implementation for your Quartz scheduler instance is an important step.\nLuckily, the choice should be a very easy one once you understand the differences between them.\nYou declare which JobStore your scheduler should use (and it's configuration settings) in the properties file (or object) that\nyou provide to the SchedulerFactory that you use to produce your scheduler instance.")]),e._v(" "),o("p",[e._v("Never use a JobStore instance directly in your code. For some reason many people attempt to do this.\nThe JobStore is for behind-the-scenes use of Quartz itself. You have to tell Quartz (through configuration) which JobStore to use, but then you should only work with the Scheduler interface in your code.")]),e._v(" "),o("h2",{attrs:{id:"ramjobstore"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#ramjobstore"}},[e._v("#")]),e._v(" RAMJobStore")]),e._v(" "),o("p",[e._v("RAMJobStore is the simplest JobStore to use, it is also the most performant (in terms of CPU time).\nRAMJobStore gets its name in the obvious way: it keeps all of its data in RAM. This is why it's lightning-fast,\nand also why it's so simple to configure. The drawback is that when your application ends (or crashes) all of\nthe scheduling information is lost - this means RAMJobStore cannot honor the setting of \"non-volatility\" on jobs and triggers.\nFor some applications this is acceptable - or even the desired behavior, but for other applications, this may be disasterous.")]),e._v(" "),o("p",[e._v("To use RAMJobStore (and assuming you're using StdSchedulerFactory) you don't need to do anything special. Default configuration\nof Quartz.NET uses RAMJobStore as job store implementation.")]),e._v(" "),o("h2",{attrs:{id:"ado-net-job-store-adojobstore"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#ado-net-job-store-adojobstore"}},[e._v("#")]),e._v(" ADO.NET Job Store (AdoJobStore)")]),e._v(" "),o("p",[e._v("AdoJobStore is also aptly named - it keeps all of its data in a database via ADO.NET.\nBecause of this it is a bit more complicated to configure than RAMJobStore, and it also is not as fast.\nHowever, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.")]),e._v(" "),o("p",[e._v('To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use.\nYou can find table-creation SQL scripts in the "database/dbtables" directory of the Quartz.NET distribution.\nIf there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB.\nOne thing to note is that in these scripts, all the the tables start with the prefix "QRTZ_"\nsuch as the tables "QRTZ_TRIGGERS", and "QRTZ_JOB_DETAIL"). This prefix can actually be anything you\'d like, as long as you inform AdoJobStore\nwhat the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables,\nfor multiple scheduler instances, within the same database.')]),e._v(" "),o("p",[e._v("Currently the only option for the internal implementation of job store is JobStoreTX which creates transactions by itself.\nThis is different from Java version of Quartz where there is also option to choose JobStoreCMT which uses J2EE container\nmanaged transactions.")]),e._v(" "),o("p",[e._v("The last piece of the puzzle is setting up a data source from which AdoJobStore can get connections to your database.\nData sources are defined in your Quartz.NET properties. Data source information contains the connection string\nand ADO.NET delegate information.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring Quartz to use JobStoreTx")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz\n")])])]),o("p",[e._v('Next, you need to select a IDriverDelegate implementation for the JobStore to use.\nThe DriverDelegate is responsible for doing any ADO.NET work that may be needed for your specific database.\nStdAdoDelegate is a delegate that uses "vanilla" ADO.NET code (and SQL statements) to do its work.\nIf there isn\'t another delegate made specifically for your database, try using this delegate -\nspecial delegates usually have better performance or workarounds for database specific issues.\nOther delegates can be found in the "Quartz.Impl.AdoJobStore" namespace, or in its sub-namespaces.')]),e._v(" "),o("p",[o("strong",[e._v("NOTE:")]),e._v(" Quartz.NET will issue warning if you are using the default StdAdoDelegate as it has poor performance\nwhen you have a lot of triggers to select from. Specific delegates have special SQL to limit result\nset length (SQLServerDelegate uses TOP n, PostgreSQLDelegate LIMIT n, OracleDelegate ROWCOUNT() <= n etc.).")]),e._v(" "),o("p",[e._v("Once you've selected your delegate, set its class name as the delegate for AdoJobStore to use.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore to use a DriverDelegate")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz\n")])])]),o("p",[e._v("Next, you need to inform the JobStore what table prefix (discussed above) you are using.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore with the Table Prefix")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.tablePrefix = QRTZ_\n")])])]),o("p",[e._v('And finally, you need to set which data source should be used by the JobStore. The named data source must also be defined in your Quartz properties.\nIn this case, we\'re specifying that Quartz should use the data source name "myDS" (that is defined elsewhere in the configuration properties).')]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore with the name of the data source to use")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.dataSource = myDS\n")])])]),o("p",[e._v("One last thing that is needed for the configuration is to set data source connection string information and database provider. Connection\nstring is the standard ADO.NET connection which is driver specific. Database provider is an abstraction of database drivers to create\nloose coupling betweeb database drivers and Quartz.")]),e._v(" "),o("p",[o("strong",[e._v("Setting Data Source's Connection String And Database Provider")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v(" quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartz;Uid=quartznet;Pwd=quartznet\n quartz.dataSource.myDS.provider = MySql-50\n")])])]),o("p",[e._v("Currently following database providers are supported:")]),e._v(" "),o("ul",[o("li",[e._v("SqlServer-11 - SQL Server driver for .NET Framework 1.1")]),e._v(" "),o("li",[e._v("SqlServer-20 - SQL Server driver for .NET Framework 2.0")]),e._v(" "),o("li",[e._v("OracleClient-20 - Microsoft's Oracle Driver (comes bundled with .NET Framework)")]),e._v(" "),o("li",[e._v("OracleODP-20 - Oracle's Oracle Driver")]),e._v(" "),o("li",[e._v("MySql-10 - MySQL Connector/.NET v. 1.0.7")]),e._v(" "),o("li",[e._v("MySql-109 - MySQL Connector/.NET v. 1.0.9")]),e._v(" "),o("li",[e._v("MySql-50 - MySQL Connector/.NET v. 5.0 (.NET 2.0)")]),e._v(" "),o("li",[e._v("MySql-51 - MySQL Connector/:NET v. 5.1 (.NET 2.0)")]),e._v(" "),o("li",[e._v("SQLite-10 - SQLite ADO.NET 2.0 Provider v. 1.0.56 (.NET 2.0)")]),e._v(" "),o("li",[e._v("Firebird-201 - Firebird ADO.NET 2.0 Provider v. 2.0.1 (.NET 2.0)")]),e._v(" "),o("li",[e._v("Firebird-210 - Firebird ADO.NET 2.0 Provider v. 2.1.0 (.NET 2.0)")])]),e._v(" "),o("p",[e._v("If your Scheduler is very busy (i.e. nearly always executing the same number of jobs as the size of the thread pool, then you should\nprobably set the number of connections in the data source to be the about the size of the thread pool + 1.This is commonly configured\nint the ADO.NET connection string - see your driver implementation for details.")]),e._v(" "),o("p",[e._v('The "quartz.jobStore.useProperties" config parameter can be set to "true" (defaults to false) in order to instruct AdoJobStore that all values in JobDataMaps will be strings,\nand therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column. This is much safer in the long term,\nas you avoid the class versioning issues that there are with serializing your non-String classes into a BLOB.')]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore to use strings as JobDataMap values (recommended)")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.useProperties = true\n")])])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/74.a79659d2.js b/assets/js/74.a79659d2.js new file mode 100644 index 000000000..8be96352d --- /dev/null +++ b/assets/js/74.a79659d2.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[74],{448:function(e,t,a){"use strict";a.r(t);var n=a(26),o=Object(n.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("p",[e._v("As mentioned previously, you can make .NET component executable by the scheduler simply by making it\nimplement the IJob interface. Here is the interface:")]),e._v(" "),a("p",[a("strong",[e._v("IJob Interface")])]),e._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("namespace")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[e._v("Quartz")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("interface")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("IJob")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("void")])]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Execute")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("JobExecutionContext")]),e._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),a("p",[e._v("In case you couldn't guess, when the job's trigger fires (more on that in a moment), the Execute(..) method\nis invoked by the scheduler. The JobExecutionContext object that is passed to this method provides\nthe job instance with information about its \"run-time\" environment - a handle to the IScheduler that executed it,\na handle to the Trigger that triggered the execution, the job's JobDetail object, and a few other items.")]),e._v(" "),a("p",[e._v("The JobDetail object is created by the Quartz.NET client (your program) at the time the Job is added\nto the scheduler. It contains various property settings for the Job, as well as a JobDataMap, which can be used\nto store state information for a given instance of your job class.")]),e._v(" "),a("p",[e._v("Trigger objects are used to trigger the execution (or 'firing') of jobs. When you wish to schedule a job,\nyou instantiate a trigger and 'tune' its properties to provide the scheduling you wish to have.\nTriggers may also have a JobDataMap associated with them - this is useful to passing parameters to a Job\nthat are specific to the firings of the trigger. Quartz.NET ships with a handful of different trigger types,\nbut the most commonly used types are SimpleTrigger and CronTrigger.")]),e._v(" "),a("p",[e._v('SimpleTrigger is handy if you need \'one-shot\' execution (just single execution of a job at a given moment in time),\nor if you need to fire a job at a given time, and have it repeat N times, with a delay of T between executions.\nCronTrigger is useful if you wish to have triggering based on calendar-like schedules - such as "every Friday,\nat noon" or "at 10:15 on the 10th day of every month."')]),e._v(" "),a("h2",{attrs:{id:"why-jobs-and-triggers"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#why-jobs-and-triggers"}},[e._v("#")]),e._v(" Why Jobs AND Triggers?")]),e._v(" "),a("p",[e._v("Many job schedulers do not have separate notions of jobs and triggers. Some define a 'job' as simply an\nexecution time (or schedule) along with some small job identifier. Others are much like the union\nof Quartz.NET's job and trigger objects. While developing Quartz for Java, Quartz team decided that it made sense to create\na separation between the schedule and the work to be performed on that schedule. This has (in our opinion)\nmany benefits.")]),e._v(" "),a("p",[e._v("For example, jobs can be created and stored in the job scheduler independent of a trigger, and many triggers\ncan be associated with the same job. Another benefit of this loose-coupling is the ability to configure jobs\nthat remain in the scheduler after their associated triggers have expired, so that that it can be rescheduled\nlater, without having to re-define it. It also allows you to modify or replace a trigger without having to\nre-define its associated job.")]),e._v(" "),a("h2",{attrs:{id:"identifiers"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#identifiers"}},[e._v("#")]),e._v(" Identifiers")]),e._v(" "),a("p",[e._v("Jobs and Triggers are given identifying names as they are registered with the Quartz.NET scheduler.\nJobs and triggers can also be placed into 'groups' which can be useful for organizing your jobs and triggers\ninto categories for later maintenance. The name of a job or trigger must be unique within its group - or in other\nwords, the true identifier of a job or trigger is its name + group. If you leave the group of the\nJob or Trigger 'null', it is equivalent to having specified SchedulerConstants.DefaultGroup.")]),e._v(" "),a("p",[e._v("You now have a general idea about what Jobs and Triggers are, you can learn more about them in\n"),a("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/more-about-jobs.html"}},[e._v("Lesson 3: More About Jobs & JobDetails")]),e._v(" and "),a("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/more-about-triggers.html"}},[e._v("Lesson 4: More About Triggers")])],1)])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/75.ac772cc7.js b/assets/js/75.ac772cc7.js new file mode 100644 index 000000000..fb4f1f5fd --- /dev/null +++ b/assets/js/75.ac772cc7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[75],{449:function(t,e,a){"use strict";a.r(e);var o=a(26),n=Object(o.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"plug-ins"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#plug-ins"}},[t._v("#")]),t._v(" Plug-Ins")]),t._v(" "),a("p",[t._v("Quartz provides an interface (ISchedulerPlugin) for plugging-in additional functionality.")]),t._v(" "),a("p",[t._v("Plugins that ship with Quartz to provide various utililty capabilities can be found documented in the Quartz.Plugins namespace.\nThey provide functionality such as auto-scheduling of jobs upon scheduler startup, logging a history of job and trigger events,\nand ensuring that the scheduler shuts down cleanly when the virtual machine exits.")]),t._v(" "),a("h2",{attrs:{id:"jobfactory"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobfactory"}},[t._v("#")]),t._v(" JobFactory")]),t._v(" "),a("p",[t._v("When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler.\nThe default JobFactory simply activates a new instance of the job class. You may want to create your own implementation\nof JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.")]),t._v(" "),a("p",[t._v("See the IJobFactory interface, and the associated Scheduler.SetJobFactory(fact) method.")]),t._v(" "),a("h2",{attrs:{id:"factory-shipped-jobs"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factory-shipped-jobs"}},[t._v("#")]),t._v(" 'Factory-Shipped' Jobs")]),t._v(" "),a("p",[t._v("Quartz also provides a number of utility Jobs that you can use in your application for doing things like sending\ne-mails and invoking remote objects. These out-of-the-box Jobs can be found documented in the Quartz.Jobs namespace.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/76.ac780687.js b/assets/js/76.ac780687.js new file mode 100644 index 000000000..225984f63 --- /dev/null +++ b/assets/js/76.ac780687.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[76],{450:function(t,a,s){"use strict";s.r(a);var e=s(26),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("As you've seen, jobs are rather easy to implement. There are just a few more things that you need to understand about\nthe nature of jobs, about the Execute(..) method of the IJob interface, and about JobDetails.")]),t._v(" "),s("p",[t._v("While a class that you implement is the actual \"job\", Quartz needs to be informed about various attributes\nthat you may wish the job to have. This is done via the JobDetail class, which was mentioned briefly in the previous section.\nSoftware 'archaeologists' may be interested to know that in an older incarnation of Quartz for Java, the implementation of the\nfunctionality of JobDetail was imposed upon the implementor of each Job class by having all of JobDetail's 'getter' methods on\nthe Job interface itself. This forced a cumbersome job of re-implementing virtually identical code on every Job class -\nwhich was really dumb... thus JobDetail class was created.")]),t._v(" "),s("p",[t._v("Let's take a moment now to discuss a bit about the 'nature' of jobs and the life-cycle of job instances within Quartz.NET.\nFirst lets take a look back at some of that snippet of code we saw in Lesson 1:")]),t._v(" "),s("p",[s("strong",[t._v("Using Quartz.NET")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// construct a scheduler factory")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" schedFact "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get a scheduler")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" sched "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" schedFact"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetScheduler")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// construct job info")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDetail")]),t._v(" jobDetail "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobDetail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token type-expression class-name"}},[t._v("DumbJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// fire every hour")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("MakeHourlyTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// start on the next even hour")]),t._v("\n trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("StartTime "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetEvenHourDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" \n trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" \n")])])]),s("p",[t._v("Now consider the job class "),s("em",[t._v("DumbJob")]),t._v(" defined as such:")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DumbJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"DumbJob is executing."')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Notice that we 'feed' the scheduler a JobDetail instance, and that it refers to the job to be executed by simply\nproviding the job's class. Each (and every) time the scheduler executes the job, it creates a new instance of the\nclass before calling its Execute(..) method. One of the ramifications of this behavior is the fact that jobs must\nhave a no-arguement constructor. Another ramification is that it does not make sense to have data-members defined\non the job class - as their values would be 'cleared' every time the job executes.")]),t._v(" "),s("p",[t._v('You may now be wanting to ask "how can I provide properties/configuration for a Job instance?" and "how can I\nkeep track of a job\'s state between executions?" The answer to these questions are the same: the key is the JobDataMap,\nwhich is part of the JobDetail object.')]),t._v(" "),s("h2",{attrs:{id:"jobdatamap"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#jobdatamap"}},[t._v("#")]),t._v(" JobDataMap")]),t._v(" "),s("p",[t._v("The JobDataMap can be used to hold any number of (serializable) objects which you wish to have made available\nto the job instance when it executes. JobDataMap is an implementation of the IDictionary interface, and has some added convenience methods for storing and retreiving data of primitive types.")]),t._v(" "),s("p",[t._v("Here's some quick snippets of putting data into the JobDataMap prior to adding the job to the scheduler:")]),t._v(" "),s("p",[s("strong",[t._v("Setting Values in a JobDataMap")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" jobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Hello World!"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n jobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3.141f")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n jobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myStateData"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("ArrayList")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" \n")])])]),s("p",[t._v("Here's a quick example of getting data from the JobDataMap during the job's execution:")]),t._v(" "),s("p",[s("strong",[t._v("Getting Values from a JobDataMap")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" instName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" instGroup "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Group"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" myFloatValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetFloat")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ArrayList")]),t._v(" state "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ArrayList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myStateData"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n state"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance {0} of DumbJob says: {1}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" instName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" jobSays"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),s("p",[t._v("If you use a persistent JobStore (discussed in the JobStore section of this tutorial) you should use some care\nin deciding what you place in the JobDataMap, because the object in it will be serialized, and they therefore\nbecome prone to class-versioning problems. Obviously standard .NET types should be very safe, but beyond that,\nanytime someone changes the definition of a class for which you have serialized instances, care has to be taken\nnot to break compatibility. Optionally, you can put AdoJobStore and JobDataMap into a mode where only primitives\nand strings can be stored in the map, thus eliminating any possibility of later serialization problems.")]),t._v(" "),s("h3",{attrs:{id:"stateful-vs-non-stateful-jobs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stateful-vs-non-stateful-jobs"}},[t._v("#")]),t._v(" Stateful vs. Non-Stateful Jobs")]),t._v(" "),s("p",[t._v("Triggers can also have JobDataMaps associated with them. This can be useful in the case where you have a Job that\nis stored in the scheduler for regular/repeated use by multiple Triggers, yet with each independent triggering,\nyou want to supply the Job with different data inputs.")]),t._v(" "),s("p",[t._v("The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge\nof the JobDataMap found on the JobDetail and the one found on the Trigger, with the value in the latter overriding\nany same-named values in the former.")]),t._v(" "),s("p",[t._v("Here's a quick example of getting data from the JobExecutionContext's merged JobDataMap during the job's execution:")]),t._v(" "),s("p",[s("strong",[t._v("Getting Values from the JobExecutionContext convenience/merged JobDataMap")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" instName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" instGroup "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Group"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note the difference from the previous example")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MergedJobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" myFloatValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetFloat")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ArrayList")]),t._v(" state "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ArrayList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myStateData"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n state"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance {0} of DumbJob says: {1}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" instName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" jobSays"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),s("h2",{attrs:{id:"statefuljob"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#statefuljob"}},[t._v("#")]),t._v(" StatefulJob")]),t._v(" "),s("p",[t._v('Now, some additional notes about a job\'s state data (aka JobDataMap): A Job instance can be defined as "stateful" or "non-stateful".\nNon-stateful jobs only have their JobDataMap stored at the time they are added to the scheduler. This means that any changes made\nto the contents of the job data map during execution of the job will be lost, and will not seen by the job the next time it executes.\nYou have probably guessed, a stateful job is just the opposite - its JobDataMap is re-stored after every execution of the job.\nOne side-effect of making a job stateful is that it cannot be executed concurrently. Or in other words: if a job is stateful, and\na trigger attempts to \'fire\' the job while it is already executing, the trigger will block (wait) until the previous execution completes.')]),t._v(" "),s("p",[t._v("You 'mark' a Job as stateful by having it implement the IStatefulJob interface, rather than the IJob interface.")]),t._v(" "),s("h2",{attrs:{id:"job-instances"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#job-instances"}},[t._v("#")]),t._v(" Job 'Instances'")]),t._v(" "),s("p",[t._v("One final point on this topic that may or may not be obvious by now: You can create a single job class, and store many\n'instance definitions' of it within the scheduler by creating multiple instances of JobDetails - each with its own set of properties\nand JobDataMap - and adding them all to the scheduler.")]),t._v(" "),s("p",[t._v("When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler. The default\nJobFactory simply calls Activator.CreateInstance behind the scenes on the job class.\nYou may want to create your own implementation of JobFactory to accomplish things such as having your application's IoC or\nDI container produce/initialize the job instance.")]),t._v(" "),s("h2",{attrs:{id:"other-attributes-of-jobs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#other-attributes-of-jobs"}},[t._v("#")]),t._v(" Other Attributes Of Jobs")]),t._v(" "),s("p",[t._v("Here's a quick summary of the other properties which can be defined for a job instance via the JobDetail object:")]),t._v(" "),s("ul",[s("li",[t._v("Durable - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it.")]),t._v(" "),s("li",[t._v("Volatile - if a job is volatile, it is not persisted between re-starts of the Quartz scheduler.")]),t._v(" "),s("li",[t._v("RequestsRecovery - if a job \"requests recovery\", and it is executing during the time of a 'hard shutdown' of the scheduler (i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. In this case, the JobExecutionContext.IsRecovering property will return true.")]),t._v(" "),s("li",[t._v("JobListeners - a job can have a set of zero or more JobListeners associated with it. When the job executes, the listeners are notified. More discussion on JobListeners can be found in the section of this document that is dedicated to the topic of TriggerListeners & JobListeners.")])]),t._v(" "),s("h2",{attrs:{id:"the-job-execute-method"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-job-execute-method"}},[t._v("#")]),t._v(" The Job.Execute(..) Method")]),t._v(" "),s("p",[t._v("Finally, we need to inform you of a few details of the IJob.Execute(..) method. The only type of exception\nthat you are allowed to throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire\ncontents of the execute method with a 'try-catch' block. You should also spend some time looking at the documentation for the\nJobExecutionException, as your job can use it to provide the scheduler various directives as to how you want the exception to be handled.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/77.b087b822.js b/assets/js/77.b087b822.js new file mode 100644 index 000000000..7ad7076d5 --- /dev/null +++ b/assets/js/77.b087b822.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[77],{451:function(t,e,s){"use strict";s.r(e);var a=s(26),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("Like jobs, triggers are relatively easy to work with, but do contain a variety of customizable options that you need to\nbe aware of and understand before you can make full use of Quartz.NET. Also, as noted earlier, there are different types of triggers,\nthat you can select to meet different scheduling needs.")]),t._v(" "),s("h2",{attrs:{id:"calendars"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#calendars"}},[t._v("#")]),t._v(" Calendars")]),t._v(" "),s("p",[t._v("Quartz Calendar objects can be associated with triggers at the time the trigger is stored in the scheduler.\nCalendars are useful for excluding blocks of time from the the trigger's firing schedule. For instance, you could\ncreate a trigger that fires a job every weekday at 9:30 am, but then add a Calendar that excludes all of the business's holidays.")]),t._v(" "),s("p",[t._v("Calendar's can be any serializable objects that implement the ICalendar interface, which looks like this:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("namespace Quartz\n{\n public interface ICalendar\n {\n string Description { get; set; }\n\n ICalendar CalendarBase { set; get; }\n\n bool IsTimeIncluded(DateTime timeUtc);\n\n DateTime GetNextIncludedTimeUtc(DateTime timeUtc);\n }\n} \n")])])]),s("p",[t._v("Notice that the parameters to these methods are of the long type. As you may guess, they are timestamps in millisecond format.\nThis means that calendars can 'block out' sections of time as narrow as a millisecond. Most likely, you'll be interested in\n'blocking-out' entire days. As a convenience, Quartz includes the class HolidayCalendar, which does just that.")]),t._v(" "),s("p",[t._v("Calendars must be instantiated and registered with the scheduler via the AddCalendar(..) method. If you use HolidayCalendar,\nafter instantiating it, you should use its AddExcludedDate(DateTime date) method in order to populate it with the days you wish\nto have excluded from scheduling. The same calendar instance can be used with multiple triggers such as this:")]),t._v(" "),s("p",[s("strong",[t._v("Using Calendars")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HolidayCalendar")]),t._v(" cal "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("HolidayCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n cal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddExcludedDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("someDate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// fire every one hour interval")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("MakeHourlyTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// start on the next even hour")]),t._v("\n trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("StartTimeUtc "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetEvenHourDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Now"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" \n trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CalendarName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. schedule job with trigger")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// fire every day at 08:00")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("MakeDailyTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// begin immediately")]),t._v("\n trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("StartTimeUtc "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" \n trigger2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n trigger2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CalendarName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. schedule job with trigger2 ")]),t._v("\n")])])]),s("p",[t._v("The details of the values passed in the SimpleTrigger constructors will be explained in the next section.\nFor now, just believe that the code above creates two triggers: one that will repeat every 60 seconds forever, and one that\nwill repeat five times with a five day interval between firings. However, any of the firings that would have\noccurred during the period excluded by the calendar will be skipped.")]),t._v(" "),s("h2",{attrs:{id:"priority"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#priority"}},[t._v("#")]),t._v(" Priority")]),t._v(" "),s("p",[t._v("Sometimes, when you have many Triggers (or few worker threads in your Quartz.NET thread pool), Quartz.NET may not have enough resources to\nimmediately fire all of the Triggers that are scheduled to fire at the same time. In this case, you may want to control\nwhich of your Triggers get first crack at the available Quartz.NET worker threads. For this purpose, you can set the priority property on a Trigger.\nIf N Triggers are to fire at the same time, but there are only Z worker threads currently available, then the first Z Triggers with the highest priority will get first dibs.\nIf you do not set a priority on a Trigger, then it will use the default priority of 5.\nAny integer value is allowed for priority, positive or negative.")]),t._v(" "),s("p",[t._v("Note: When a Trigger is detected to require recovery, its recovery is scheduled with the same priority as the original Trigger.")]),t._v(" "),s("p",[s("strong",[t._v("Priority Example")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// All three Triggers will be scheduled to fire 5 minutes from now.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DateTime")]),t._v(" d "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddMinutes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trig1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"T1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"MyGroup"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" d"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trig2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"T2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"MyGroup"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" d"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trig3 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"T3"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"MyGroup"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" d"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDetail")]),t._v(" jobDetail "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobDetail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"MyJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"MyGroup"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token type-expression class-name"}},[t._v("NoOpJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger1 does not have its priority set, so it defaults to 5")]),t._v("\n sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trig1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger2 has its priority set to 10")]),t._v("\n trig2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" jobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n trig2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Priority "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trig2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger2 has its priority set to 1")]),t._v("\n trig3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" jobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n trig3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Priority "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trig3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Five minutes from now, when the scheduler invokes these three triggers")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// they will be allocated worker threads in decreasing order of their")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// priority: Trigger2(10), Trigger1(5), Trigger3(1) ")]),t._v("\n")])])]),s("h2",{attrs:{id:"misfire-instructions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#misfire-instructions"}},[t._v("#")]),t._v(" Misfire Instructions")]),t._v(" "),s("p",[t._v('Another important property of a Trigger is its "misfire instruction". A misfire occurs if a persistent trigger "misses"\nits firing time because of the scheduler being shutdown, or because there are no available threads in Quartz\'s thread pool for executing the job.\nThe different trigger types have different misfire instructions available to them. By default they use a \'smart policy\' instruction')]),t._v(" "),s("ul",[s("li",[t._v("which has dynamic behavior based on trigger type and configuration. When the scheduler starts, it searches for any persistent triggers that\nhave misfired, and it then updates each of them based on their individually configured misfire instructions.")])]),t._v(" "),s("p",[t._v("When you start using Quartz in your\nown projects, you should make yourself familiar with the misfire instructions that are defined on the given trigger types,\nand explained in their API documentation. More specific information about misfire instructions will be given within\nthe tutorial lessons specific to each trigger type. The misfire instruction for a given trigger instance can be configured\nusing the MisfireInstruction property.")]),t._v(" "),s("h2",{attrs:{id:"triggerutils-triggers-made-easy"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#triggerutils-triggers-made-easy"}},[t._v("#")]),t._v(" TriggerUtils - Triggers Made Easy")]),t._v(" "),s("p",[t._v("The TriggerUtils class contains conveniences to help you create triggers and dates without\nhaving to monkey around with DateTime objects. Use this class to easily make triggers that fire every minute,\nhour, day, week, month, etc. Also use this class to generate dates that are rounded to the nearest second, minute or hour -\nthis can be very useful for setting trigger start-times.")]),t._v(" "),s("h2",{attrs:{id:"trigger-listeners"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#trigger-listeners"}},[t._v("#")]),t._v(" Trigger Listeners")]),t._v(" "),s("p",[t._v("Finally, triggers may have registered listeners, just as jobs may.\nObjects implementing the ITriggerListener interface will receive notifications as a trigger is fired.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/78.0c35c107.js b/assets/js/78.0c35c107.js new file mode 100644 index 000000000..78cf4f7e9 --- /dev/null +++ b/assets/js/78.0c35c107.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[78],{452:function(s,t,a){"use strict";a.r(t);var e=a(26),n=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("p",[s._v("SchedulerListeners are much like ITriggerListeners and IJobListeners, except they receive notification of\nevents within the scheduler itself - not necessarily events related to a specific trigger or job.")]),s._v(" "),a("p",[s._v("Scheduler-related events include: the addition of a job/trigger, the removal of a job/trigger, a serious error\nwithin the scheduler, notification of the scheduler being shutdown, and others.")]),s._v(" "),a("p",[a("strong",[s._v("The ISchedulerListener Interface")])]),s._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("interface")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("ISchedulerListener")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobScheduled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Trigger")]),s._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobUnscheduled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggerFinalized")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Trigger")]),s._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggersPaused")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggersResumed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobsPaused")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobsResumed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("SchedulerError")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" msg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("SchedulerException")]),s._v(" cause"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n \n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("SchedulerShutdown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" \n")])])]),a("p",[s._v("ISchedulerListener instances are created and registered in much the same way as the other listener types,\nexcept there is no distinction between global and non-global listeners. Scheduler listeners can be\nvirtually any object that implements the ISchedulerListener interface.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/79.c0acd288.js b/assets/js/79.c0acd288.js new file mode 100644 index 000000000..63ad1b2e1 --- /dev/null +++ b/assets/js/79.c0acd288.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[79],{453:function(t,e,s){"use strict";s.r(e);var a=s(26),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time,\nor at a specific moment in time followed by repeats at a specific interval. Or plainer english, if you want the trigger to\nfire at exactly 11:23:54 AM on January 13, 2005, and then fire five more times, every ten seconds.")]),t._v(" "),s("p",[t._v("With this description, you may not find it surprising to find that the properties of a SimpleTrigger include: a start-time,\nand end-time, a repeat count, and a repeat interval. All of these properties are exactly what you'd expect them to be, with\nonly a couple special notes related to the end-time property.")]),t._v(" "),s("p",[t._v("The repeat count can be zero, a positive integer, or the constant value SimpleTrigger.RepeatIndefinitely.\nThe repeat interval property must be TimeSpan.Zero, or a positive TimeSpan value.\nNote that a repeat interval of zero will cause 'repeat count' firings of the trigger to happen concurrently\n(or as close to concurrently as the scheduler can manage).")]),t._v(" "),s("p",[t._v("If you're not already familiar with the DateTime class, you may find it helpful for computing your trigger fire-times,\ndepending on the startTimeUtc (or endTimeUtc) that you're trying to create. The TriggerUtils class is also helpful in this respect.")]),t._v(" "),s("p",[t._v("The EndTimeUtc property (if it is specified) over-rides the repeat count property. This can be useful if you wish to create a trigger\nsuch as one that fires every 10 seconds until a given moment in time - rather than having to compute the number of times it would\nrepeat between the start-time and the end-time, you can simply specify the end-time and then use a repeat count of RepeatIndefinitely\n(you could even specify a repeat count of some huge number that is sure to be more than the number of times the trigger will actually\nfire before the end-time arrives).")]),t._v(" "),s("p",[t._v("SimpleTrigger has a few different constructors, but we'll examine this one, and use it in the few examples that follow:")]),t._v(" "),s("p",[s("strong",[t._v("One of SimpleTrigger's Constructors")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("group")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DateTime")]),t._v(" startTimeUtc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n NullableDateTime "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("endTime")]),t._v(" endTimeUtc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")])]),t._v(" repeatCount"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TimeSpan")]),t._v(" repeatInterval"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[s("strong",[t._v("SimpleTrigger Example 1 - Create a trigger that fires exactly once, ten seconds from now")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SimpleTrigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n TimeSpan"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Zero"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[s("strong",[t._v("SimpleTrigger Example 2 - Create a trigger that fires immediately, then repeats every 60 seconds, forever")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SimpleTrigger")]),t._v(" trigger2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n SimpleTrigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("RepeatIndefinitely"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n TimeSpan"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[s("strong",[t._v("SimpleTrigger Example 3 - Create a trigger that fires immediately, then repeats every 10 seconds until 40 seconds from now")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v("TimeSpan"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SimpleTrigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myGroup"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n DateTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("40")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n SimpleTrigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("RepeatIndefinitely"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n TimeSpan"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[s("strong",[t._v("SimpleTrigger Example 4 - Create a trigger that fires on March 17 of the year 2002 at precisely 10:30 am, and repeats 5 times\n(for a total of 6 firings) - with a 30 second delay between each firing")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DateTime")]),t._v(" startTime "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("DateTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2002")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("17")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ToUniversalTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SimpleTrigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("SimpleTrigger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n startTime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n TimeSpan"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("Spend some time looking at the other constructors (and property setters) available on SimpleTrigger, so that you can use the\none most convenient to what you want to accomplish.")]),t._v(" "),s("h3",{attrs:{id:"simpletrigger-misfire-instructions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#simpletrigger-misfire-instructions"}},[t._v("#")]),t._v(" SimpleTrigger Misfire Instructions")]),t._v(" "),s("p",[t._v("SimpleTrigger has several instructions that can be used to inform Quartz what it should do when a misfire occurs.\n(Misfire situations were introduced in the More About Triggers section of this tutorial).\nThese instructions are defined as constants on MisfirePolicy.SimpleTrigger (including API documentation describing their behavior).\nThe instructions include:")]),t._v(" "),s("p",[s("strong",[t._v("Misfire Instruction Constants of SimpleTrigger")])]),t._v(" "),s("ul",[s("li",[t._v("MisfirePolicy.SimpleTrigger.FireNow")]),t._v(" "),s("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNowWithExistingRepeatCount")]),t._v(" "),s("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNowWithRemainingRepeatCount")]),t._v(" "),s("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNextWithRemainingCount")]),t._v(" "),s("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNextWithExistingCount")])]),t._v(" "),s("p",[t._v("You should recall from the earlier lessons that all triggers have the MisfirePolicy.SmartPolicy instruction available for use,\nand this instruction is also the default for all trigger types.")]),t._v(" "),s("p",[t._v("If the 'smart policy' instruction is used, SimpleTrigger dynamically chooses between its various MISFIRE instructions, based on the configuration\nand state of the given SimpleTrigger instance. The documentation for the SimpleTrigger.UpdateAfterMisfire() method explains the exact details of\nthis dynamic behavior.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/8.d0570d6e.js b/assets/js/8.d0570d6e.js new file mode 100644 index 000000000..add341311 --- /dev/null +++ b/assets/js/8.d0570d6e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{383:function(t,n,r){"use strict";r.r(n);r(49),r(29),r(181),r(27);var e={computed:{posts:function(){return this.$site.pages.filter((function(t){return"post"===t.id&&!0!==t.frontmatter.hidden&&!1!==t.frontmatter.promote})).sort((function(t,n){return n.path.localeCompare(t.path)})).slice(0,5).map((function(t){return t.dateString=t.path.substring(1,11),t}))}}},o=r(26),i=Object(o.a)(e,(function(){var t=this,n=t.$createElement,r=t._self._c||n;return r("div",t._l(t.posts,(function(n){return r("ul",[r("li",[r("router-link",{attrs:{to:n.path}},[t._v(t._s(n.dateString+" "+n.frontmatter.title))])],1)])})),0)}),[],!1,null,null,null);n.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/80.f966b0e7.js b/assets/js/80.f966b0e7.js new file mode 100644 index 000000000..eee0382bb --- /dev/null +++ b/assets/js/80.f966b0e7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[80],{454:function(t,e,s){"use strict";s.r(e);var n=s(26),a=Object(n.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("Listeners are objects that you create to perform actions based on events occuring within the scheduler.\nAs you can probably guess, TriggerListeners receive events related to triggers, and JobListeners receive events related to jobs.")]),t._v(" "),s("p",[t._v('Trigger-related events include: trigger firings, trigger mis-firings (discussed in the "Triggers" section of this document),\nand trigger completions (the jobs fired off by the trigger is finished).')]),t._v(" "),s("p",[s("strong",[t._v("The ITriggerListener Interface")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITriggerListener")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Name "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerFired")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("VetoJobExecution")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerMisfired")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerComplete")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")])]),t._v(" triggerInstructionCode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Job-related events include: a notification that the job is about to be executed, and a notification when the job has completed execution.")]),t._v(" "),s("p",[s("strong",[t._v("The IJobListener Interface")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobListener")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Name "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobToBeExecuted")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobExecutionVetoed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobWasExecuted")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionException")]),t._v(" jobException"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),s("h2",{attrs:{id:"using-your-own-listeners"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#using-your-own-listeners"}},[t._v("#")]),t._v(" Using Your Own Listeners")]),t._v(" "),s("p",[t._v('To create a listener, simply create an object the implements either the ITriggerListener and/or IJobListener interface.\nListeners are then registered with the scheduler during run time, and must be given a name (or rather, they must advertise their own\nname via their Name property. Listeners can be registered as either "global" or "non-global".\nGlobal listeners receive events for ALL triggers/jobs, and non-global listeners receive events only for the specific triggers/jobs that\nexplicitely name the listener in their GetTriggerListenerNames() or GetJobListenerNames() properties.')]),t._v(" "),s("p",[t._v("As described above, listeners are registered with the scheduler during run time, and are NOT stored in the JobStore along with the jobs and triggers.\nThe jobs and triggers only have the names of the related listeners stored with them. Hence, each time your application runs, the listeners\nneed to be re-registered with the scheduler.")]),t._v(" "),s("p",[s("strong",[t._v("Adding a JobListener to the Scheduler")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("scheduler.AddGlobalJobListener(myJobListener);\n")])])]),s("p",[t._v("or")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("scheduler.AddJobListener(myJobListener);\n")])])]),s("p",[t._v("Listeners are not used by most users of Quartz.NET, but are handy when application requirements create the need\nfor the notification of events, without the Job itself explicitly notifying the application.")])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/81.a91e6c4f.js b/assets/js/81.a91e6c4f.js new file mode 100644 index 000000000..683937f82 --- /dev/null +++ b/assets/js/81.a91e6c4f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[81],{455:function(t,s,a){"use strict";a.r(s);var n=a(26),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("Before you can use the scheduler, it needs to be instantiated (who'd have guessed?).\nTo do this, you use an implementor of ISchedulerFactory.")]),t._v(" "),a("p",[t._v("Once a scheduler is instantiated, it can be started, placed in stand-by mode, and shutdown.\nNote that once a scheduler is shutdown, it cannot be restarted without being re-instantiated.\nTriggers do not fire (jobs do not execute) until the scheduler has been started, nor while it is\nin the paused state.")]),t._v(" "),a("p",[t._v("Here's a quick snippet of code, that instantiates and starts a scheduler, and schedules a job for execution:")]),t._v(" "),a("p",[a("strong",[t._v("Using Quartz.NET")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// construct a scheduler factory")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" schedFact "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get a scheduler")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" sched "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" schedFact"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetScheduler")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n sched"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// construct job info")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDetail")]),t._v(" jobDetail "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobDetail")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token type-expression class-name"}},[t._v("HelloJob")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// fire every hour")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Trigger")]),t._v(" trigger "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("MakeHourlyTrigger")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// start on the next even hour")]),t._v("\n trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("StartTimeUtc "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerUtils"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetEvenHourDate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n sched"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("jobDetail"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("As you can see, working with Quartz.NET is rather simple. In "),a("RouterLink",{attrs:{to:"/documentation/quartz-1.x/tutorial/jobs-and-triggers.html"}},[t._v("Lesson 2")]),t._v(" we'll give a quick overview of Jobs and Triggers, so that you can more fully understand this example.")],1)])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/82.d6972444.js b/assets/js/82.d6972444.js new file mode 100644 index 000000000..0fd1d574d --- /dev/null +++ b/assets/js/82.d6972444.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[82],{456:function(t,e,n){"use strict";n.r(e);var s=n(26),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/83.5fb1964c.js b/assets/js/83.5fb1964c.js new file mode 100644 index 000000000..8dfec989e --- /dev/null +++ b/assets/js/83.5fb1964c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[83],{457:function(t,e,n){"use strict";n.r(e);var s=n(26),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("p",[e("strong",[this._v("Sorry, not ready yet!")])])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/84.11a39734.js b/assets/js/84.11a39734.js new file mode 100644 index 000000000..51cd20eb3 --- /dev/null +++ b/assets/js/84.11a39734.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[84],{458:function(e,t,a){"use strict";a.r(t);var s=a(26),n=Object(s.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("p",[a("em",[e._v("This document outlines changes needed per version upgrade basis. You need to check the steps for each version you are jumping over. You should also check "),a("a",{attrs:{href:"https://raw.github.com/quartznet/quartznet/master/changelog.txt",target:"_blank",rel:"noopener noreferrer"}},[e._v("the complete change log"),a("OutboundLink")],1),e._v(".")])]),e._v(" "),a("p",[a("strong",[e._v("If you are a new user starting with the latest version, you don't need to follow this guide. Just jump right to "),a("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/index.html"}},[e._v("the tutorial")])],1)]),e._v(" "),a("h2",{attrs:{id:"upgrading-to-2-2-from-2-1"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-2-2-from-2-1"}},[e._v("#")]),e._v(" Upgrading to 2.2 from 2.1")]),e._v(" "),a("h3",{attrs:{id:"database-schema-changes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#database-schema-changes"}},[e._v("#")]),e._v(" Database schema changes")]),e._v(" "),a("p",[e._v("Database schema has changed to include the scheduled time for fired triggers table. You need to run the migration script:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[e._v("database\\schema_20_to_22_upgrade.sql\n")])])]),a("p",[a("strong",[e._v("Make sure you check the scheduler name in the script - the default value of sched_name column is TestScheduler! If you have existing data the scheduler name should correspond to your existing scheduler name in Quartz configuration (quartz.scheduler.instanceName).")])]),e._v(" "),a("h3",{attrs:{id:"other"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#other"}},[e._v("#")]),e._v(" Other")]),e._v(" "),a("ul",[a("li",[e._v("SchedulerStarting() method was added to ISchedulerListener interface")]),e._v(" "),a("li",[e._v("dbFailureRetryInterval parameter was removed from DirectSchedulerFactory API")])]),e._v(" "),a("p",[e._v("There are variations for different database server inside the script. Choose the one suiting you the best.")]),e._v(" "),a("h2",{attrs:{id:"upgrading-to-2-1-from-2-0"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-2-1-from-2-0"}},[e._v("#")]),e._v(" Upgrading to 2.1 from 2.0")]),e._v(" "),a("ul",[a("li",[e._v("NthIncludedDayTrigger was removed that was supposed to be removed in 2.0")]),e._v(" "),a("li",[e._v("There are no Visual Studio 2008 solutions and projects anymore, you need VS2010 or later")])]),e._v(" "),a("h2",{attrs:{id:"upgrading-to-2-0-from-1-0"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-2-0-from-1-0"}},[e._v("#")]),e._v(" Upgrading to 2.0 from 1.0")]),e._v(" "),a("h3",{attrs:{id:"database-schema-changes-2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#database-schema-changes-2"}},[e._v("#")]),e._v(" Database schema changes")]),e._v(" "),a("p",[e._v("Database has changed since 1.0 version. You need to run the database migration script:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",[a("code",[e._v("database\\sqlserver_schema_10_to_20_upgrade.sql\n")])])]),a("p",[e._v("The script is made for SQL Server, but should work for others. You can adapt the script when needed for your specific database. "),a("strong",[e._v("Always test the migration on non-production server before upgrading production")])]),e._v(" "),a("h3",{attrs:{id:"api-changes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#api-changes"}},[e._v("#")]),e._v(" API Changes")]),e._v(" "),a("p",[e._v("The most obvious differences with version 2.0 are the significant changes to the API.\nThese changes have aimed to: modernize the API to use collections and generics, remove ambiguities and redundancies,\nhide/remove methods that should not be public to client code, improve separation of concerns, and introduce\na Domain Specific Language (DSL) for working with the core entities (jobs and triggers).")]),e._v(" "),a("p",[e._v('While the API changes are significant, and the usage of the "new way of doing things" is highly encouraged,\nthere are some formulaic (search-and-replace) techniques that can be used to get 1.x code quickly working with version 2.0.\nSee the migration guide for more information.')]),e._v(" "),a("p",[a("strong",[e._v("Outline of most significant API changes:")])]),e._v(" "),a("p",[e._v("API methods that return (or take as parameters) arrays now return (or take) typed collections.\nFor example, rather than GetJobGroupNames(): string[] we now have GetJobGroupNames(): IList\nJob and Trigger identification is now based on JobKey and TriggerKey. Keys include both a name and group.\nMethods which operate on particular jobs/triggers now take keys as the parameter. For example, GetTrigger(TriggerKey key): ITrigger,\nrather than GetTrigger(string name, string group): Trigger.\nITrigger is now an interface, rather than a class. Likewise for ISimpleTrigger, ICronTrigger, etc.\nNew DSL/builder-based API for construction Jobs and Triggers:")]),e._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("IJobDetail")]),e._v(" job "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" JobBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Create")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("<")]),e._v("SimpleJob"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"job1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("ITrigger")]),e._v(" trigger "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" TriggerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"trigger1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("StartAt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("DateBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("FutureDate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" IntervalUnit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("Hour"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("WithSimpleSchedule")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=>")]),e._v(" x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("RepeatHourlyForever")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("ModifiedByCalendar")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('"holidays"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n")])])]),a("p",[e._v("Methods from TriggerUtils related to easy construction of Dates have been moved to new DateBuilder class,\nthat can be used with static imports to nicely create Date instances for trigger start and end times, etc.")]),e._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// build a date for 9:00 am on Halloween")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("DateTimeOffset")]),e._v(" runDate "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" DateBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("DateOf")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("31")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// build a date 2 hours in the future")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("DateTimeOffset")]),e._v(" myDate "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" DateBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("FutureDate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" IntervalUnit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("Hour"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n")])])]),a("p",[e._v("The IStatefulJob interface has been deprecated in favor of new class-level attributes for IJob implementations\n(using both attributes produces equivalent to that of the old IStatefulJob interface):")]),e._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// instructs the scheduler to re-store the Job's JobDataMap contents after execution completes")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("PersistJobDataAfterExecution"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("class")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("MyJob")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(":")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("IJob")])]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// instructs the scheduler to block other instances of the same job (by JobKey) from executing when one already is")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("DisallowConcurrentExecution"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("class")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("MyJob")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(":")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token type-list"}},[a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("IJob")])]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),a("p",[a("strong",[e._v("Significant changes to usage of JobListener and TriggerListener")])]),e._v(" "),a("ul",[a("li",[e._v('Removal of distinction between "global" and "non-global" listeners')]),e._v(" "),a("li",[e._v("JobDetails and Triggers are no longer configured with a list of names of listeners to notify, instead listeners identify which jobs/triggers they're interested in.")]),e._v(" "),a("li",[e._v("Listeners are now assigned a set of Matcher instances - which provide matching rules for jobs/triggers they wish to receive events for.")]),e._v(" "),a("li",[e._v("Listeners are now managed through a ListenerManager API, rather than directly with the Scheduler API.")])]),e._v(" "),a("p",[a("strong",[e._v("Other changes")])]),e._v(" "),a("ul",[a("li",[e._v("The SchedulerException class and class hierarchy has been cleaned up.")]),e._v(" "),a("li",[e._v("DateIntervalTrigger was renamed to CalendarIntervalTrigger (or more exactly the concrete class is now CalendarIntervalTriggerImpl).")]),e._v(" "),a("li",[e._v('The notion (property) of "volatility" of jobs and triggers has been eliminated.')]),e._v(" "),a("li",[e._v("New trigger misfire instruction MisfireInstruction.IgnoreMisfirePolicy lets a trigger be configured in such a way\nthat it is selectively ignored from all misfire handling. In other words, it will fire as soon as it can, with no special handling -\na great option for improving performance particularly with setups that have lots of one-shot (non-repeating) triggers.")]),e._v(" "),a("li",[e._v("Trigger's CompareTo() method now correctly relates to its Equals() method, in that it compares the trigger's key, rather than next fire time.\nA new Comparator that sorts triggers according to fire time, priority and key was added as Trigger.TriggerTimeComparator.")])]),e._v(" "),a("h2",{attrs:{id:"new-features"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#new-features"}},[e._v("#")]),e._v(" New Features")]),e._v(" "),a("ul",[a("li",[e._v("Scheduler.Clear() method provides convenient (and dangerous!) way to remove all jobs, triggers and calendars from the scheduler.")]),e._v(" "),a("li",[e._v("Scheduler.ScheduleJobs(IDictionary> triggersAndJobs, boolean replace) method provides convenient bulk addition of jobs and triggers.")]),e._v(" "),a("li",[e._v("Scheduler.UnscheduleJobs(IList triggerKeys) method provides convenient bulk unscheduling of jobs.")]),e._v(" "),a("li",[e._v("Scheduler.DeleteJobs(IList jobKeys) method provides convenient bulk deletion of jobs (and related triggers).")]),e._v(" "),a("li",[e._v("Scheduler.CheckExists(JobKey jobKey) and Scheduler.CheckExists(TriggerKey triggerKey) methods provides convenient way to determine uniqueness of job/trigger keys (as opposed to old have of having to retrieve the job/trigger by name and then check whether the result was null).")]),e._v(" "),a("li",[e._v("AdoJobStore now allows one set of tables to be used by multiple distinct scheduler instances")]),e._v(" "),a("li",[e._v("AdoJobStore is now capable of storing non-core Trigger implementations without using BLOB columns, through the use of the new TriggerPersistenceDelegate interface, which can (optionally) be implemented by implementers of custom Trigger types.")]),e._v(" "),a("li",[e._v('Cron expressions now support the ability to specify an offset for "last day of month" and "last weekday of month" expressions. For examples: "L-3" (three days back from the last of the month) or "L-3W" (nearest weekday to the day three days back from the last day of the month).')]),e._v(" "),a("li",[e._v('XML files containing scheduling data now have a way to specify trigger start times as offsets into the future from the time the file is processed (useful for triggers that need to begin firing some time after the application is launched/deployed).\nFrom schema: ')]),e._v(" "),a("li",[e._v("XML file schema now supports specifying the 'priority' property of triggers.")]),e._v(" "),a("li",[e._v("Added DirectoryScanJob to core jobs that ship with Quartz, also added minimum age parameter to pre-existing FileScanJob.")])]),e._v(" "),a("h2",{attrs:{id:"miscellaneous"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#miscellaneous"}},[e._v("#")]),e._v(" Miscellaneous")]),e._v(" "),a("p",[e._v("Various performance improvements, including (but not limited to):")]),e._v(" "),a("ul",[a("li",[e._v("Ability to batch-acquire triggers that are ready to be fired, which can provide performance improvements for very busy schedulers")]),e._v(" "),a("li",[e._v('Methods for batch addition/removal of jobs and triggers (see "New Features")')]),e._v(" "),a("li",[e._v("Triggers have a new misfire instruction option, MisfireInstruction.IgnoreMisfirePolicy, which may be useful if you do not require misfire handling for your trigger(s), and want to take advantage of a performance gain")])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/85.7a20170c.js b/assets/js/85.7a20170c.js new file mode 100644 index 000000000..1a09e7656 --- /dev/null +++ b/assets/js/85.7a20170c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[85],{459:function(t,a,s){"use strict";s.r(a);var n=s(26),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("Welcome to the Quick Start Guide for Quartz.NET. As you read this guide, expect to see details of:")]),t._v(" "),s("ul",[s("li",[t._v("Downloading Quartz.NET")]),t._v(" "),s("li",[t._v("Installing Quartz.NET")]),t._v(" "),s("li",[t._v("Configuring Quartz to your own particular needs")]),t._v(" "),s("li",[t._v("Starting a sample application")])]),t._v(" "),s("h2",{attrs:{id:"download-and-install"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#download-and-install"}},[t._v("#")]),t._v(" Download and Install")]),t._v(" "),s("p",[t._v("You can either download the zip file or use the NuGet package. NuGet package contains only the binaries needed to run Quartz.NET, zip file comes with source code, samples and Quartz.NET server sample application.")]),t._v(" "),s("h3",{attrs:{id:"zip-archive"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#zip-archive"}},[t._v("#")]),t._v(" Zip Archive")]),t._v(" "),s("p",[s("strong",[t._v("Short version")]),t._v(": Once you've downloaded Quartz.NET, unzip it somewhere, grab the Quartz.dll and Common.Logging.dll from bin directory and start to use them.")]),t._v(" "),s("p",[t._v("Quartz depends only on single third-party library called Common.Logging (which contains logging abstractions that allow you to use the logging provider that suites you the best).\nYou need to have Quartz.dll and Commong.Logging.dll beside your app binaries to successfully run Quartz.NET. So just add them as references to your Visual Studio project that uses them.\nYou can find these dlls from extracted archive from path "),s("strong",[t._v("bin\\your-target-framework-version\\release\\Quartz")]),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"nuget-package"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#nuget-package"}},[t._v("#")]),t._v(" NuGet Package")]),t._v(" "),s("p",[t._v("Couldn't get any simpler than this. Just fire up Visual Studio (with NuGet installed) and add reference to package "),s("strong",[t._v("Quartz")]),t._v(" from package manager extension:")]),t._v(" "),s("ul",[s("li",[t._v("Right-click on your project's References and choose "),s("strong",[t._v("Manage NuGet Packages...")])]),t._v(" "),s("li",[t._v("Choose "),s("strong",[t._v("Online")]),t._v(" category from the left")]),t._v(" "),s("li",[t._v("Enter "),s("strong",[t._v("Quartz")]),t._v(" to the top right search and hit enter")]),t._v(" "),s("li",[t._v("Choose "),s("strong",[t._v("Quartz.NET")]),t._v(" from search results and hit install")]),t._v(" "),s("li",[t._v("Done!")])]),t._v(" "),s("p",[t._v("or from NuGet Command-Line:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("Install-Package Quartz\n")])])]),s("h2",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[t._v("#")]),t._v(" Configuration")]),t._v(" "),s("p",[t._v("This is the big bit! Quartz.NET is a very configurable library. There are three ways (which are not mutually exclusive) to supply Quartz.NET configuration information:")]),t._v(" "),s("ul",[s("li",[t._v("Programmatically via providing NameValueCollection parameter to scheduler factory")]),t._v(" "),s("li",[t._v("Via standard youapp.exe.config configuration file using quartz-element")]),t._v(" "),s("li",[t._v("quartz.config file in your application's root directory")])]),t._v(" "),s("p",[t._v("You can find samples of all these alternatives in the Quartz.NET zip file.")]),t._v(" "),s("p",[t._v("Full documentation of available properties is available in the "),s("RouterLink",{attrs:{to:"/documentation/quartz-2.x/configuration/index.html"}},[t._v("Quartz Configuration Reference")]),t._v(".")],1),t._v(" "),s("p",[t._v("To get up and running quickly, a basic quartz.config looks something like this:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("quartz.scheduler.instanceName = MyScheduler\nquartz.threadPool.threadCount = 3\nquartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz\n")])])]),s("p",[t._v("Remember to set the "),s("strong",[t._v("Copy to Output Directory")]),t._v(" on Visual Studio's file property pages to have value "),s("strong",[t._v("Copy always")]),t._v(". Otherwise the config will not be seen if it's not in build directory.")]),t._v(" "),s("p",[t._v("The scheduler created by this configuration has the following characteristics:")]),t._v(" "),s("ul",[s("li",[t._v('quartz.scheduler.instanceName - This scheduler\'s name will be "MyScheduler".')]),t._v(" "),s("li",[t._v("quartz.threadPool.threadCount - There are 3 threads in the thread pool, which means that a maximum of 3 jobs can be run simultaneously.")]),t._v(" "),s("li",[t._v("quartz.jobStore.type - All of Quartz's data, such as details of jobs and triggers, is held in memory (rather than in a database).\nEven if you have a database and want to use it with Quartz, I suggest you get Quartz working with the RamJobStore before you open up a whole new dimension by working with a database.")])]),t._v(" "),s("p",[s("em",[t._v("Actually you don't need to define these properties if you don't want to, Quartz.NET comes with sane defaults")])]),t._v(" "),s("h2",{attrs:{id:"starting-a-sample-application"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#starting-a-sample-application"}},[t._v("#")]),t._v(" Starting a Sample Application")]),t._v(" "),s("p",[t._v("Now you've downloaded and installed Quartz, it's time to get a sample application up and running. The following code obtains an instance of the scheduler, starts it, then shuts it down:")]),t._v(" "),s("p",[s("strong",[t._v("Program.cs")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Threading")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("namespace")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("QuartzSampleApplication")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Program")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Grab the Scheduler instance from the Factory ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" scheduler "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" StdSchedulerFactory"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetDefaultScheduler")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and start it off")]),t._v("\n scheduler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// some sleep to show what's happening")]),t._v("\n Thread"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Sleep")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeSpan"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and last shut down the scheduler when you are ready to close your program")]),t._v("\n scheduler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Shutdown")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SchedulerException")]),t._v(" se"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("se"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Once you obtain a scheduler using StdSchedulerFactory.GetDefaultScheduler(), your application will not terminate by default until you call scheduler.Shutdown(), because there will be active threads (non-daemon threads).")]),t._v(" "),s("p",[t._v("Now running the program will not show anything. When 10 seconds have passed the program will just terminate. Lets add some logging to console.")]),t._v(" "),s("h2",{attrs:{id:"adding-logging"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#adding-logging"}},[t._v("#")]),t._v(" Adding logging")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://netcommon.sourceforge.net/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Common.Logging"),s("OutboundLink")],1),t._v(" can be configured to use different logging frameworks under the hood; namely Enterprise Library, Log4Net and NLog.")]),t._v(" "),s("p",[t._v("However, to keep things simple for our example we take the simple route and configure logging using code to just log to the console using Common.Logging basic logging mechanism.")]),t._v(" "),s("p",[t._v("Add the following line to the beginning of your Program.cs")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};\n")])])]),s("h2",{attrs:{id:"trying-out-the-application-and-adding-jobs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#trying-out-the-application-and-adding-jobs"}},[t._v("#")]),t._v(" Trying out the application and adding jobs")]),t._v(" "),s("p",[t._v("Now we should get a lot more information when we start the application.")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("11.1.2014 14:52:04 [INFO] Quartz.Impl.StdSchedulerFactory - Quartz.NET properties loaded from configuration file 'c:\\ConsoleApplication1\\bin\\Debug\\quartz.config'\n11.1.2014 14:52:04 [INFO] Quartz.Impl.StdSchedulerFactory - Using default implementation for object serializer\n11.1.2014 14:52:04 [INFO] Quartz.Impl.StdSchedulerFactory - Using default implementation for ThreadExecutor\n11.1.2014 14:52:04 [INFO] Quartz.Core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl\n11.1.2014 14:52:04 [INFO] Quartz.Core.QuartzScheduler - Quartz Scheduler v.2.2.1.400 created.\n11.1.2014 14:52:04 [INFO] Quartz.Simpl.RAMJobStore - RAMJobStore initialized.\n11.1.2014 14:52:04 [INFO] Quartz.Core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.1.400) 'MyScheduler' with instanceId 'NON_CLUSTERED'\n Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.\n NOT STARTED.\n Currently in standby mode.\n Number of jobs executed: 0\n Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 3 threads.\n Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.\n\n11.1.2014 14:52:04 [INFO] Quartz.Impl.StdSchedulerFactory - Quartz scheduler 'MyScheduler' initialized\n11.1.2014 14:52:04 [INFO] Quartz.Impl.StdSchedulerFactory - Quartz scheduler version: 2.2.1.400\n11.1.2014 14:52:04 [INFO] Quartz.Core.QuartzScheduler - Scheduler MyScheduler_$_NON_CLUSTERED started.\n")])])]),s("p",[t._v("We need a simple test job to test the functionality, lets create HelloJob that outputs greetings to console.")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HelloJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\tConsole"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Greetings from HelloJob!"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("To do something interesting, you need code just after Start() method, before the Thread.Sleep.")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"job1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then repeat every 10 seconds")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Tell quartz to schedule the job using our trigger")]),t._v("\nscheduler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("The complete console application will now look like this")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Threading")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("using")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Job")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("namespace")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ConsoleApplication1")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Program")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")])]),t._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Logging"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LogManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Adapter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("Common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Logging"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Simple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ConsoleOutLoggerFactoryAdapter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("Level "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Logging"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LogLevel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Info"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Grab the Scheduler instance from the Factory ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" scheduler "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" StdSchedulerFactory"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetDefaultScheduler")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and start it off")]),t._v("\n scheduler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"job1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then repeat every 10 seconds")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Tell quartz to schedule the job using our trigger")]),t._v("\n scheduler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// some sleep to show what's happening")]),t._v("\n Thread"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Sleep")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeSpan"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("FromSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// and last shut down the scheduler when you are ready to close your program")]),t._v("\n scheduler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Shutdown")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SchedulerException")]),t._v(" se"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("se"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Press any key to close the application"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ReadKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HelloJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Greetings from HelloJob!"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Now go have some fun exploring Quartz.NET! You can continue by reading "),s("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/index.html"}},[t._v("the tutorial")]),t._v(".")],1)])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/86.f892a53a.js b/assets/js/86.f892a53a.js new file mode 100644 index 000000000..0760555e7 --- /dev/null +++ b/assets/js/86.f892a53a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[86],{460:function(t,o,e){"use strict";e.r(o);var r=e(26),s=Object(r.a)({},(function(){var t=this,o=t.$createElement,e=t._self._c||o;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h2",{attrs:{id:"choose-a-lesson"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#choose-a-lesson"}},[t._v("#")]),t._v(" Choose a lesson:")]),t._v(" "),e("ul",[e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/using-quartz.html"}},[t._v("Lesson 1: Using Quartz")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/jobs-and-triggers.html"}},[t._v("Lesson 2: Jobs And Triggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/more-about-jobs.html"}},[t._v("Lesson 3: More About Jobs & JobDetails")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/more-about-triggers.html"}},[t._v("Lesson 4: More About Triggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/simpletriggers.html"}},[t._v("Lesson 5: SimpleTriggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/crontriggers.html"}},[t._v("Lesson 6: CronTriggers")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/trigger-and-job-listeners.html"}},[t._v("Lesson 7: TriggerListeners & JobListeners")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/scheduler-listeners.html"}},[t._v("Lesson 8: SchedulerListeners")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/job-stores.html"}},[t._v("Lesson 9: JobStores")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/configuration-resource-usage-and-scheduler-factory.html"}},[t._v("Lesson 10: Configuration, Resource Usage and SchedulerFactory")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/advanced-enterprise-features.html"}},[t._v("Lesson 11: Advanced (Enterprise) Features")])],1),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/miscellaneous-features.html"}},[t._v("Lesson 12: Miscellaneous Features")])],1)])])}),[],!1,null,null,null);o.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/87.0a9e471c.js b/assets/js/87.0a9e471c.js new file mode 100644 index 000000000..80a882c72 --- /dev/null +++ b/assets/js/87.0a9e471c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[87],{461:function(e,t,r){"use strict";r.r(t);var n=r(26),i=Object(n.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h2",{attrs:{id:"clustering"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#clustering"}},[e._v("#")]),e._v(" Clustering")]),e._v(" "),r("p",[e._v('Clustering currently only works with the AdoJobstore (JobStoreTX). Features include load-balancing and job fail-over (if the JobDetail\'s "request recovery" flag is set to true).')]),e._v(" "),r("p",[e._v('Enable clustering by setting the "quartz.jobStore.clustered" property to "true".\nEach instance in the cluster should use the same copy of the quartz properties.\nExceptions of this would be to use properties that are identical, with the following allowable exceptions:\nDifferent thread pool size, and different value for the "quartz.scheduler.instanceId" property.\nEach node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing "AUTO" as the value of this property.')]),e._v(" "),r("p",[e._v("Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly\n(the clocks must be within a second of each other). See "),r("a",{attrs:{href:"http://www.boulder.nist.gov/timefreq/service/its.htm"}},[e._v("http://www.boulder.nist.gov/timefreq/service/its.htm")]),e._v("\nif you are unfamiliar with how to do this.")]),e._v(" "),r("p",[e._v("Never fire-up a non-clustered instance against the same set of tables that any other instance is running against.\nYou may get serious data corruption, and will definitely experience eratic behavior.")])])}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/88.677da331.js b/assets/js/88.677da331.js new file mode 100644 index 000000000..33b2a593c --- /dev/null +++ b/assets/js/88.677da331.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[88],{462:function(e,t,o){"use strict";o.r(t);var r=o(26),n=Object(r.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v('Quartz is architected in modular way, and therefore to get it running, several components need to be "snapped" together.\nFortunately, some helpers exist for making this happen.')]),e._v(" "),o("p",[e._v("The major components that need to be configured before Quartz can do its work are:")]),e._v(" "),o("ul",[o("li",[e._v("ThreadPool")]),e._v(" "),o("li",[e._v("JobStore")]),e._v(" "),o("li",[e._v("DataSources (if necessary)")]),e._v(" "),o("li",[e._v("The Scheduler itself")])]),e._v(" "),o("p",[e._v("The ThreadPool provides a set of Threads for Quartz to use when executing Jobs.\nThe more threads in the pool, the greater number of Jobs that can run concurrently.\nHowever, too many threads may bog-down your system.\nMost Quartz users find that 5 or so threads are plenty- because they have fewer than 100 jobs at any given time,\nthe jobs are not generally scheduled to run at the same time, and the jobs are short-lived (complete quickly).\nOther users find that they need 10, 15, 50 or even 100 threads - because they have tens-of-thousands\nof triggers with various schedules - which end up having an average of between 10 and 100 jobs trying to\nexecute at any given moment. Finding the right size for your scheduler's pool is completely dependent on\nwhat you're using the scheduler for. There are no real rules, other than to keep the number of threads as\nsmall as possible (for the sake of your machine's resources) - but make sure you have enough for your Jobs to fire on time.\nNote that if a trigger's time to fire arrives, and there isn't an available thread,\nQuartz will block (pause) until a thread comes available, then the Job will execute -\nsome number of milliseconds later than it should have. This may even cause the tread to misfire - if\nthere is no available thread for the duration of the scheduler's configured \"misfire threshold\".")]),e._v(" "),o("p",[e._v("A IThreadPool interface is defined in the Quartz.Spi namespace, and you can create a IThreadPool implementation in any way you like.\nQuartz ships with a simple (but very satisfactory) thread pool named Quartz.Simpl.SimpleThreadPool.\nThis IThreadPool implementation simply maintains a fixed set of threads in its pool - never grows, never shrinks.\nBut it is otherwise quite robust and is very well tested - as nearly everyone using Quartz uses this pool.")]),e._v(" "),o("p",[e._v("JobStores and DataSrouces were discussed in Lesson 9 of this tutorial. Worth noting here, is the fact that all JobStores\nimplement the IJobStore interface - and that if one of the bundled JobStores does not fit your needs, then you can make your own.")]),e._v(" "),o("p",[e._v("Finally, you need to create your Scheduler instance. The Scheduler itself needs to be given a name and handed\ninstances of a JobStore and ThreadPool.")]),e._v(" "),o("h2",{attrs:{id:"stdschedulerfactory"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#stdschedulerfactory"}},[e._v("#")]),e._v(" StdSchedulerFactory")]),e._v(" "),o("p",[e._v("StdSchedulerFactory is an implementation of the ISchedulerFactory interface.\nIt uses a set of properties (NameValueCollection) to create and initialize a Quartz Scheduler.\nThe properties are generally stored in and loaded from a file, but can also be created by your program and handed directly to the factory.\nSimply calling getScheduler() on the factory will produce the scheduler, initialize it (and its ThreadPool, JobStore and DataSources),\nand return a handle to its public interface.")]),e._v(" "),o("p",[e._v('There are some sample configurations (including descriptions of the properties) in the "docs/config" directory of the Quartz distribution.\nYou can find complete documentation in the "Configuration" manual under the "Reference" section of the Quartz documentation.')]),e._v(" "),o("h2",{attrs:{id:"directschedulerfactory"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#directschedulerfactory"}},[e._v("#")]),e._v(" DirectSchedulerFactory")]),e._v(" "),o("p",[e._v("DirectSchedulerFactory is another SchedulerFactory implementation. It is useful to those wishing to create their Scheduler\ninstance in a more programatic way. Its use is generally discouraged for the following reasons: (1) it\nrequires the user to have a greater understanding of what they're doing, and (2) it does not allow for declaritive\nconfiguration - or in other words, you end up hard-coding all of the scheduler's settings.")]),e._v(" "),o("h2",{attrs:{id:"logging"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#logging"}},[e._v("#")]),e._v(" Logging")]),e._v(" "),o("p",[e._v("Quartz.NET uses the "),o("a",{attrs:{href:"http://netcommon.sourceforge.net/"}},[e._v("Common.Logging framework")]),e._v(' for all of its logging needs.\nQuartz does not produce much logging information - generally just some information during initialization, and\nthen only messages about serious problems while Jobs are executing. In order to "tune" the logging settings\n(such as the amount of output, and where the output goes), you need to understand the Commmon.Logging framework,\nwhich is beyond the scope of this document, please refer to '),o("a",{attrs:{href:"http://netcommon.sourceforge.net/documentation.html"}},[e._v("Common.Logging Documentation")]),e._v(".")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/89.52251cd3.js b/assets/js/89.52251cd3.js new file mode 100644 index 000000000..676fd0a9c --- /dev/null +++ b/assets/js/89.52251cd3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[89],{463:function(t,e,a){"use strict";a.r(e);var i=a(26),n=Object(i.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"introduction"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),a("p",[t._v("cron is a UNIX tool that has been around for a long time, so its scheduling capabilities are powerful and proven. The CronTrigger class is based on the scheduling capabilities of cron.")]),t._v(" "),a("p",[t._v('CronTrigger uses "cron expressions", which are able to create firing schedules such as: "At 8:00am every Monday through Friday" or "At 1:30am every last Friday of the month".')]),t._v(" "),a("p",[t._v("Cron expressions are powerful, but can be pretty confusing. This tutorial aims to take some of the mystery out of creating a cron expression, giving users a resource which they can visit before having to ask in a forum or mailing list.")]),t._v(" "),a("h2",{attrs:{id:"format"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#format"}},[t._v("#")]),t._v(" Format")]),t._v(" "),a("p",[t._v("A cron expression is a string comprised of 6 or 7 fields separated by white space.\nFields can contain any of the allowed values, along with various combinations of the allowed special characters for that field. The fields are as follows:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",[a("strong",[t._v("Field Name")])]),t._v(" "),a("th",[a("strong",[t._v("Mandatory")])]),t._v(" "),a("th",[a("strong",[t._v("Allowed Values")])]),t._v(" "),a("th",[a("strong",[t._v("Allowed Special Characters")])])])]),t._v(" "),a("tbody",[a("tr",[a("td",[t._v("Seconds")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("0-59")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Minutes")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("0-59")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Hours")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("0-23")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Day of month")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("1-31")]),t._v(" "),a("td",[t._v(", - * ? / L W")])]),t._v(" "),a("tr",[a("td",[t._v("Month")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("1-12 or JAN-DEC")]),t._v(" "),a("td",[t._v(", - * /")])]),t._v(" "),a("tr",[a("td",[t._v("Day of week")]),t._v(" "),a("td",[t._v("YES")]),t._v(" "),a("td",[t._v("1-7 or SUN-SAT")]),t._v(" "),a("td",[t._v(", - * ? / L #")])]),t._v(" "),a("tr",[a("td",[t._v("Year")]),t._v(" "),a("td",[t._v("NO")]),t._v(" "),a("td",[t._v("empty, 1970-2099")]),t._v(" "),a("td",[t._v(", - * /")])])])]),t._v(" "),a("p",[t._v("So cron expressions can be as simple as this: * * * * ? *")]),t._v(" "),a("p",[t._v("or more complex, like this: 0/5 14,18,3-39,52 * ? JAN,MAR,SEP MON-FRI 2002-2010")]),t._v(" "),a("h2",{attrs:{id:"special-characters"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#special-characters"}},[t._v("#")]),t._v(" Special characters")]),t._v(" "),a("ul",[a("li",[a("ul",[a("li",[t._v('("all values") - used to select all values within a field. For example, "" in the minute field means *"every minute".')])])]),t._v(" "),a("li",[a("strong",[t._v("?")]),t._v(' ("no specific value") - useful when you need to specify something in one of the two fields in which the character is allowed, but not the other. For example, if I want my trigger to fire on a particular day of the month (say, the 10th), but don\'t care what day of the week that happens to be, I would put "10" in the day-of-month field, and "?" in the day-of-week field. See the examples below for clarification.')]),t._v(" "),a("li",[a("strong",[t._v("-")]),t._v(' - used to specify ranges. For example, "10-12" in the hour field means "the hours 10, 11 and 12".')]),t._v(" "),a("li",[a("strong",[t._v(",")]),t._v(' - used to specify additional values. For example, "MON,WED,FRI" in the day-of-week field means "the days Monday, Wednesday, and Friday".')]),t._v(" "),a("li",[a("strong",[t._v("/")]),t._v(" - used to specify increments. For example, \"0/15\" in the seconds field means \"the seconds 0, 15, 30, and 45\". And \"5/15\" in the seconds field means \"the seconds 5, 20, 35, and 50\". You can also specify '/' after the '' character - in this case '' is equivalent to having '0' before the '/'. '1/3' in the day-of-month field means \"fire every 3 days starting on the first day of the month\".")]),t._v(" "),a("li",[a("strong",[t._v("L")]),t._v(' ("last") - has different meaning in each of the two fields in which it is allowed. For example, the value "L" in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - for example "6L" means "the last friday of the month". You can also specify an offset from the last day of the month, such as "L-3" which would mean the third-to-last day of the calendar month. When using the \'L\' option, it is important not to specify lists, or ranges of values, as you\'ll get confusing/unexpected results.')]),t._v(" "),a("li",[a("strong",[t._v("W")]),t._v(" (\"weekday\") - used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify \"15W\" as the value for the day-of-month field, the meaning is: \"the nearest weekday to the 15th of the month\". So if the 15th is a Saturday, the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. However if you specify \"1W\" as the value for day-of-month, and the 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not 'jump' over the boundary of a month's days. The 'W' character can only be specified when the day-of-month is a single day, not a range or list of days.\n** The 'L' and 'W' characters can also be combined in the day-of-month field to yield 'LW', which translates to "),a("em",[t._v('"last weekday of the month"')]),t._v(".")]),t._v(" "),a("li",[a("strong",[t._v("#")]),t._v(' - used to specify "the nth" XXX day of the month. For example, the value of "6#3" in the day-of-week field means "the third Friday of the month" (day 6 = Friday and "#3" = the 3rd one in the month). Other examples: "2#1" = the first Monday of the month and "4#5" = the fifth Wednesday of the month. Note that if you specify "#5" and there is not 5 of the given day-of-week in the month, then no firing will occur that month.\n** The legal characters and the names of months and days of the week are not case sensitive. MON is the same as mon.')])]),t._v(" "),a("h2",{attrs:{id:"examples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[t._v("#")]),t._v(" Examples")]),t._v(" "),a("p",[t._v("Here are some full examples:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",{staticStyle:{"text-align":"left"}},[a("strong",[t._v("Expression")])]),t._v(" "),a("th",{staticStyle:{"text-align":"left"}},[a("strong",[t._v("Meaning")])])])]),t._v(" "),a("tbody",[a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0 12 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 12pm (noon) every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * *")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 * * ? *")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 * * ? 2005")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every day during the year 2005")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 * 14 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every minute starting at 2pm and ending at 2:59pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0/5 14 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0/5 14,18 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0-5 14 * * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every minute starting at 2pm and ending at 2:05pm, every day")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 10,44 14 ? 3 WED")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * MON-FRI")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 15 * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the 15th day of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 L * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the last day of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 L-2 * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the 2nd-to-last last day of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6L")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the last Friday of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6L")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the last Friday of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6L 2002-2005")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 15 10 ? * 6#3")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 10:15am on the third Friday of every month")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 0 12 1/5 * ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire at 12pm (noon) every 5 days every month, starting on the first day of the month.")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("0 11 11 11 11 ?")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("Fire every November 11th at 11:11am.")])])])]),t._v(" "),a("ul",[a("li",[t._v("Pay attention to the effects of '?' and '*' in the day-of-week and day-of-month fields!")])]),t._v(" "),a("h2",{attrs:{id:"notes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#notes"}},[t._v("#")]),t._v(" Notes")]),t._v(" "),a("ul",[a("li",[t._v("Support for specifying both a day-of-week and a day-of-month value is not complete (you must currently use the '?' character in one of these fields).")]),t._v(" "),a("li",[t._v('Be careful when setting fire times between the hours of the morning when "daylight savings" changes occur in your locale (for US locales, this would typically be the hour before and after 2:00 AM - because the time shift can cause a skip or a repeat depending on whether the time moves back or jumps forward. You may find this wikipedia entry helpful in determining the specifics to your locale:\nhttps://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world')])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/9.f3852c3d.js b/assets/js/9.f3852c3d.js new file mode 100644 index 000000000..d03e681f4 --- /dev/null +++ b/assets/js/9.f3852c3d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{384:function(t,n,r){"use strict";r.r(n);r(49),r(181),r(27);var e={computed:{posts:function(){return this.$site.pages.filter((function(t){return"post"===t.id&&!0!==t.frontmatter.hidden})).sort((function(t,n){return n.path.localeCompare(t.path)})).map((function(t){return t.dateString=t.path.substring(1,11),t}))}}},o=r(26),i=Object(o.a)(e,(function(){var t=this,n=t.$createElement,r=t._self._c||n;return r("div",t._l(t.posts,(function(n){return r("div",[r("h2",[r("router-link",{attrs:{to:n.path}},[t._v(t._s(n.dateString+" "+n.frontmatter.title))])],1),t._v(" "),r("p",[t._v(t._s(n.frontmatter.description))]),t._v(" "),r("p",[r("router-link",{attrs:{to:n.path}},[t._v("Read more")])],1)])})),0)}),[],!1,null,null,null);n.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/90.88b29d89.js b/assets/js/90.88b29d89.js new file mode 100644 index 000000000..5a66b5303 --- /dev/null +++ b/assets/js/90.88b29d89.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[90],{464:function(t,s,n){"use strict";n.r(s);var e=n(26),a=Object(e.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[t._v("CronTriggers are often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions,\nrather than on the exactly specified intervals of SimpleTrigger.")]),t._v(" "),n("p",[t._v('With CronTrigger, you can specify firing-schedules such as "every Friday at noon", or "every weekday and 9:30 am",\nor even "every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday".')]),t._v(" "),n("p",[t._v("Even so, like SimpleTrigger, CronTrigger has a startTime which specifies when the schedule is in force, and an (optional)\nendTime that specifies when the schedule should be discontinued.")]),t._v(" "),n("h3",{attrs:{id:"cron-expressions"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#cron-expressions"}},[t._v("#")]),t._v(" Cron Expressions")]),t._v(" "),n("p",[n("em",[t._v("Cron-Expressions")]),t._v(" are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up\nof seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:")]),t._v(" "),n("ul",[n("li",[n("ol",[n("li",[t._v("Seconds")])])]),t._v(" "),n("li",[n("ol",{attrs:{start:"2"}},[n("li",[t._v("Minutes")])])]),t._v(" "),n("li",[n("ol",{attrs:{start:"3"}},[n("li",[t._v("Hours")])])]),t._v(" "),n("li",[n("ol",{attrs:{start:"4"}},[n("li",[t._v("Day-of-Month")])])]),t._v(" "),n("li",[n("ol",{attrs:{start:"5"}},[n("li",[t._v("Month")])])]),t._v(" "),n("li",[n("ol",{attrs:{start:"6"}},[n("li",[t._v("Day-of-Week")])])]),t._v(" "),n("li",[n("ol",{attrs:{start:"7"}},[n("li",[t._v("Year (optional field)")])])])]),t._v(" "),n("p",[t._v('An example of a complete cron-expression is the string "0 0 12 ? * WED" - which means "every Wednesday at 12:00 pm".')]),t._v(" "),n("p",[t._v('Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED")\nexample could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".')]),t._v(" "),n("p",[t._v("Wild-cards (the '"),n("em",[t._v("' character) can be used to say \"every\" possible value of this field. Therefore the '")]),t._v('\' character in the\n"Month" field of the previous example simply means "every month". A \'*\' in the Day-Of-Week field would obviously mean "every day of the week".')]),t._v(" "),n("p",[t._v("All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers\n0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful\nabout how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings\nJAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday)\nor by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.")]),t._v(" "),n("p",[t._v("The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes,\nstarting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour,\nstarting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.")]),t._v(" "),n("p",[t._v("The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify \"no specific value\".\nThis is useful when you need to specify something in one of the two fields, but not the other.\nSee the examples below (and CronTrigger API documentation) for clarification.")]),t._v(" "),n("p",[t._v('The \'L\' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last",\nbut it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means\n"the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself,\nit simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" -\nfor example "6L" or "FRIL" both mean "the last friday of the month". When using the \'L\' option, it is important not to specify lists,\nor ranges of values, as you\'ll get confusing results.')]),t._v(" "),n("p",[t._v('The \'W\' is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month".')]),t._v(" "),n("p",[t._v('The \'#\' is used to specify "the nth" XXX weekday of the month. For example, the value of "6#3" or "FRI#3" in the day-of-week field means "the third Friday of the month".')]),t._v(" "),n("h2",{attrs:{id:"example-cron-expressions"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#example-cron-expressions"}},[t._v("#")]),t._v(" Example Cron Expressions")]),t._v(" "),n("p",[t._v("Here are a few more examples of expressions and their meanings - you can find even more in the API documentation for CronTrigger")]),t._v(" "),n("p",[n("strong",[t._v("CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes")])]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v('"0 0/5 * * * ?"\n')])])]),n("p",[n("strong",[t._v("CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).")])]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v('"10 0/5 * * * ?"\n')])])]),n("p",[n("strong",[t._v("CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.")])]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v('"0 30 10-13 ? * WED,FRI"\n')])])]),n("p",[n("strong",[t._v("CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month.\nNote that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30")])]),t._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",[n("code",[t._v('"0 0/30 8-9 5,20 * ?"\n')])])]),n("p",[t._v('Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am,\nand every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.')]),t._v(" "),n("h2",{attrs:{id:"building-crontriggers"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#building-crontriggers"}},[t._v("#")]),t._v(" Building CronTriggers")]),t._v(" "),n("p",[t._v("CronTrigger instances are built using "),n("strong",[t._v("TriggerBuilder")]),t._v(" (for the trigger's main properties) and "),n("strong",[t._v("WithCronSchedule")]),t._v(" extension method (for the CronTrigger-specific properties).")]),t._v(" "),n("p",[t._v("You can also use CronScheduleBuilder's static methods to create schedules.")]),t._v(" "),n("p",[n("strong",[t._v("Build a trigger that will fire every other minute, between 8am and 5pm, every day:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 0/2 8-17 * * ?"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire daily at 10:42 am:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// we use CronScheduleBuilder's static helper methods here")]),t._v("\ntrigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("DailyAtHourAndMinute")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("or -")]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 42 10 * * ?"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire on Wednesdays at 10:42 am, in a TimeZone other than the system's default:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WeeklyOnDayAndHourAndMinute")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DayOfWeek"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Wednesday"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("InTimeZone")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeZoneInfo"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FindSystemTimeZoneById")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Central America Standard Time"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("or -")]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 42 10 ? * WED"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("InTimeZone")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TimeZoneInfo"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FindSystemTimeZoneById")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Central America Standard Time"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"crontrigger-misfire-instructions"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#crontrigger-misfire-instructions"}},[t._v("#")]),t._v(" CronTrigger Misfire Instructions")]),t._v(" "),n("p",[t._v("The following instructions can be used to inform Quartz what it should do when a misfire occurs for CronTrigger.\n(Misfire situations were introduced in the More About Triggers section of this tutorial). These instructions are defined in as\nconstants (and API documentation has description for their behavior). The instructions include:")]),t._v(" "),n("ul",[n("li",[t._v("MisfireInstruction.IgnoreMisfirePolicy")]),t._v(" "),n("li",[t._v("MisfireInstruction.CronTrigger.DoNothing")]),t._v(" "),n("li",[t._v("MisfireInstruction.CronTrigger.FireOnceNow")])]),t._v(" "),n("p",[t._v("All triggers have the MisfireInstrution.SmartPolicy instruction available for use, and this instruction is also the default for all trigger types.\nThe 'smart policy' instruction is interpreted by CronTrigger as MisfireInstruction.CronTrigger.FireOnceNow. The API documentation for the\nCronTrigger.UpdateAfterMisfire() method explains the exact details of this behavior.")]),t._v(" "),n("p",[t._v("When building CronTriggers, you specify the misfire instruction as part of the cron schedule (via WithCronSchedule extension method):")]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithCronSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 0/2 8-17 * * ?"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithMisfireHandlingInstructionFireAndProceed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/91.4a66f8db.js b/assets/js/91.4a66f8db.js new file mode 100644 index 000000000..5b4ff598b --- /dev/null +++ b/assets/js/91.4a66f8db.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[91],{465:function(e,t,o){"use strict";o.r(t);var a=o(26),r=Object(a.a)({},(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("p",[e._v("JobStore's are responsible for keeping track of all the \"work data\" that you give to the scheduler:\njobs, triggers, calendars, etc. Selecting the appropriate IJobStore implementation for your Quartz scheduler instance is an important step.\nLuckily, the choice should be a very easy one once you understand the differences between them.\nYou declare which JobStore your scheduler should use (and it's configuration settings) in the properties file (or object) that\nyou provide to the SchedulerFactory that you use to produce your scheduler instance.")]),e._v(" "),o("p",[o("em",[e._v("Never use a JobStore instance directly in your code. For some reason many people attempt to do this.\nThe JobStore is for behind-the-scenes use of Quartz itself. You have to tell Quartz (through configuration) which JobStore to use,\nbut then you should only work with the Scheduler interface in your code.")])]),e._v(" "),o("h2",{attrs:{id:"ramjobstore"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#ramjobstore"}},[e._v("#")]),e._v(" RAMJobStore")]),e._v(" "),o("p",[e._v("RAMJobStore is the simplest JobStore to use, it is also the most performant (in terms of CPU time).\nRAMJobStore gets its name in the obvious way: it keeps all of its data in RAM. This is why it's lightning-fast,\nand also why it's so simple to configure. The drawback is that when your application ends (or crashes) all of\nthe scheduling information is lost - this means RAMJobStore cannot honor the setting of \"non-volatility\" on jobs and triggers.\nFor some applications this is acceptable - or even the desired behavior, but for other applications, this may be disasterous.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring Quartz to use RAMJobStore")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz\n")])])]),o("p",[e._v("To use RAMJobStore (and assuming you're using StdSchedulerFactory) you don't need to do anything special. Default configuration\nof Quartz.NET uses RAMJobStore as job store implementation.")]),e._v(" "),o("h2",{attrs:{id:"ado-net-job-store-adojobstore"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#ado-net-job-store-adojobstore"}},[e._v("#")]),e._v(" ADO.NET Job Store (AdoJobStore)")]),e._v(" "),o("p",[e._v("AdoJobStore is also aptly named - it keeps all of its data in a database via ADO.NET.\nBecause of this it is a bit more complicated to configure than RAMJobStore, and it also is not as fast.\nHowever, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.")]),e._v(" "),o("p",[e._v('To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use.\nYou can find table-creation SQL scripts in the "database/dbtables" directory of the Quartz.NET distribution.\nIf there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB.\nOne thing to note is that in these scripts, all the the tables start with the prefix "QRTZ_"\nsuch as the tables "QRTZ_TRIGGERS", and "QRTZ_JOB_DETAIL"). This prefix can actually be anything you\'d like, as long as you inform AdoJobStore\nwhat the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables,\nfor multiple scheduler instances, within the same database.')]),e._v(" "),o("p",[e._v("Currently the only option for the internal implementation of job store is JobStoreTX which creates transactions by itself.\nThis is different from Java version of Quartz where there is also option to choose JobStoreCMT which uses J2EE container\nmanaged transactions.")]),e._v(" "),o("p",[e._v("The last piece of the puzzle is setting up a data source from which AdoJobStore can get connections to your database.\nData sources are defined in your Quartz.NET properties. Data source information contains the connection string\nand ADO.NET delegate information.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring Quartz to use JobStoreTx")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz\n")])])]),o("p",[e._v('Next, you need to select a IDriverDelegate implementation for the JobStore to use.\nThe DriverDelegate is responsible for doing any ADO.NET work that may be needed for your specific database.\nStdAdoDelegate is a delegate that uses "vanilla" ADO.NET code (and SQL statements) to do its work.\nIf there isn\'t another delegate made specifically for your database, try using this delegate -\nspecial delegates usually have better performance or workarounds for database specific issues.\nOther delegates can be found in the "Quartz.Impl.AdoJobStore" namespace, or in its sub-namespaces.')]),e._v(" "),o("p",[o("strong",[e._v("NOTE:")]),e._v(" Quartz.NET will issue warning if you are using the default StdAdoDelegate as it has poor performance\nwhen you have a lot of triggers to select from. Specific delegates have special SQL to limit result\nset length (SQLServerDelegate uses TOP n, PostgreSQLDelegate LIMIT n, OracleDelegate ROWCOUNT() <= n etc.).")]),e._v(" "),o("p",[e._v("Once you've selected your delegate, set its class name as the delegate for AdoJobStore to use.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore to use a DriverDelegate")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz\n")])])]),o("p",[e._v("Next, you need to inform the JobStore what table prefix (discussed above) you are using.")]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore with the Table Prefix")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.tablePrefix = QRTZ_\n")])])]),o("p",[e._v('And finally, you need to set which data source should be used by the JobStore. The named data source must also be defined in your Quartz properties.\nIn this case, we\'re specifying that Quartz should use the data source name "myDS" (that is defined elsewhere in the configuration properties).')]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore with the name of the data source to use")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.dataSource = myDS\n")])])]),o("p",[e._v("One last thing that is needed for the configuration is to set data source connection string information and database provider. Connection\nstring is the standard ADO.NET connection which is driver specific. Database provider is an abstraction of database drivers to create\nloose coupling between database drivers and Quartz.")]),e._v(" "),o("p",[o("strong",[e._v("Setting Data Source's Connection String And Database Provider")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v(" quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartz;Uid=quartznet;Pwd=quartznet\n quartz.dataSource.myDS.provider = MySql-50\n")])])]),o("p",[e._v("Currently following database providers are supported:")]),e._v(" "),o("ul",[o("li",[e._v("SqlServer-20 - SQL Server driver for .NET Framework 2.0")]),e._v(" "),o("li",[e._v("OracleODP-20 - Oracle's Oracle Driver")]),e._v(" "),o("li",[e._v("OracleODPManaged-1123-40 Oracle's managed driver for Oracle 11")]),e._v(" "),o("li",[e._v("OracleODPManaged-1211-40 Oracle's managed driver for Oracle 12")]),e._v(" "),o("li",[e._v("MySql-50 - MySQL Connector/.NET v. 5.0 (.NET 2.0)")]),e._v(" "),o("li",[e._v("MySql-51 - MySQL Connector/:NET v. 5.1 (.NET 2.0)")]),e._v(" "),o("li",[e._v("MySql-65 - MySQL Connector/:NET v. 6.5 (.NET 2.0)")]),e._v(" "),o("li",[e._v("SQLite-10 - SQLite ADO.NET 2.0 Provider v. 1.0.56 (.NET 2.0)")]),e._v(" "),o("li",[e._v("Firebird-201 - Firebird ADO.NET 2.0 Provider v. 2.0.1 (.NET 2.0)")]),e._v(" "),o("li",[e._v("Firebird-210 - Firebird ADO.NET 2.0 Provider v. 2.1.0 (.NET 2.0)")]),e._v(" "),o("li",[e._v("Npgsql-20 - PostgreSQL Npgsql")])]),e._v(" "),o("p",[o("strong",[e._v("You can and should use latest version of driver if newer is available, just create an assembly binding redirect")])]),e._v(" "),o("p",[e._v("If your Scheduler is very busy (i.e. nearly always executing the same number of jobs as the size of the thread pool, then you should\nprobably set the number of connections in the data source to be the about the size of the thread pool + 1.This is commonly configured\nint the ADO.NET connection string - see your driver implementation for details.")]),e._v(" "),o("p",[e._v('The "quartz.jobStore.useProperties" config parameter can be set to "true" (defaults to false) in order to instruct AdoJobStore that all values in JobDataMaps will be strings,\nand therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column. This is much safer in the long term,\nas you avoid the class versioning issues that there are with serializing your non-String classes into a BLOB.')]),e._v(" "),o("p",[o("strong",[e._v("Configuring AdoJobStore to use strings as JobDataMap values (recommended)")])]),e._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",[o("code",[e._v("quartz.jobStore.useProperties = true\n")])])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/92.46584aef.js b/assets/js/92.46584aef.js new file mode 100644 index 000000000..b8e751f2e --- /dev/null +++ b/assets/js/92.46584aef.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[92],{466:function(t,e,a){"use strict";a.r(e);var s=a(26),n=Object(s.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"the-quartz-api"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#the-quartz-api"}},[t._v("#")]),t._v(" The Quartz API")]),t._v(" "),a("p",[t._v("The key interfaces and classes of the Quartz API are:")]),t._v(" "),a("ul",[a("li",[t._v("IScheduler - the main API for interacting with the scheduler.")]),t._v(" "),a("li",[t._v("IJob - an interface to be implemented by components that you wish to have executed by the scheduler.")]),t._v(" "),a("li",[t._v("IJobDetail - used to define instances of Jobs.")]),t._v(" "),a("li",[t._v("ITrigger - a component that defines the schedule upon which a given Job will be executed.")]),t._v(" "),a("li",[t._v("JobBuilder - used to define/build JobDetail instances, which define instances of Jobs.")]),t._v(" "),a("li",[t._v("TriggerBuilder - used to define/build Trigger instances.")])]),t._v(" "),a("p",[t._v("In this tutorial for readability's sake following terms are used interchangeably: IScheduler and Scheduler, IJob and Job, IJobDetail and JobDetail, ITrigger and Trigger.")]),t._v(" "),a("p",[t._v("A "),a("strong",[t._v("Scheduler")]),t._v("'s life-cycle is bounded by it's creation, via a "),a("strong",[t._v("SchedulerFactory")]),t._v(" and a call to its Shutdown() method.\nOnce created the IScheduler interface can be used to add, remove, and list Jobs and Triggers, and perform other scheduling-related operations (such as pausing a trigger).\nHowever, the Scheduler will not actually act on any triggers (execute jobs) until it has been started with the Start() method, as shown in "),a("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/using-quartz.html"}},[t._v("Lesson 1")]),t._v(".")],1),t._v(" "),a("p",[t._v('Quartz provides "builder" classes that define a Domain Specific Language (or DSL, also sometimes referred to as a "fluent interface"). In the previous lesson you saw an example of it, which we present a portion of here again:')]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token generic-method"}},[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token generic class-name"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// name "myJob", group "group1"')]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then every 40 seconds")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("40")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Tell quartz to schedule the job using our trigger")]),t._v("\n\tsched"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("scheduleJob")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("The block of code that builds the job definition is using JobBuilder using fluent interface to create the product, IJobDetail.\nLikewise, the block of code that builds the trigger is using TriggerBuilder's fluent interface and extension methods that are specific to given trigger type.\nPossible schedule extension methods are:")]),t._v(" "),a("ul",[a("li",[t._v("WithCalendarIntervalSchedule")]),t._v(" "),a("li",[t._v("WithCronSchedule")]),t._v(" "),a("li",[t._v("WithDailyTimeIntervalSchedule")]),t._v(" "),a("li",[t._v("WithSimpleSchedule")])]),t._v(" "),a("p",[t._v("The DateBuilder class contains various methods for easily constructing DateTimeOffset instances for particular points in time (such as a date that represents the next even hour - or in other words 10:00:00 if it is currently 9:43:27).")]),t._v(" "),a("h2",{attrs:{id:"jobs-and-triggers"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobs-and-triggers"}},[t._v("#")]),t._v(" Jobs and Triggers")]),t._v(" "),a("p",[t._v("A Job is a class that implements the IJob interface, which has only one simple method:")]),t._v(" "),a("p",[a("strong",[t._v("IJob Interface")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("namespace")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("When the Job's trigger fires (more on that in a moment), the Execute(..) method is invoked by one of the scheduler's worker threads.\nThe JobExecutionContext object that is passed to this method provides the job instance with information about its \"run-time\" environment -\na handle to the Scheduler that executed it, a handle to the Trigger that triggered the execution, the job's JobDetail object, and a few other items.")]),t._v(" "),a("p",[t._v("The JobDetail object is created by the Quartz.NET client (your program) at the time the Job is added to the scheduler.\nIt contains various property settings for the Job, as well as a JobDataMap, which can be used to store state information for a given instance of your job class.\nIt is essentially the definition of the job instance, and is discussed in further detail in the next lesson.")]),t._v(" "),a("p",[t._v("Trigger objects are used to trigger the execution (or 'firing') of jobs. When you wish to schedule a job, you instantiate a trigger and 'tune' its properties\nto provide the scheduling you wish to have. Triggers may also have a JobDataMap associated with them - this is useful to passing parameters to a\nJob that are specific to the firings of the trigger. Quartz ships with a handful of different trigger types, but the most commonly used types\nare SimpleTrigger (interface ISimpleTrigger) and CronTrigger (interface ICronTrigger).")]),t._v(" "),a("p",[t._v('SimpleTrigger is handy if you need \'one-shot\' execution (just single execution of a job at a given moment in time), or if you need to fire a job at a given time,\nand have it repeat N times, with a delay of T between executions. CronTrigger is useful if you wish to have triggering based on calendar-like schedules -\nsuch as "every Friday, at noon" or "at 10:15 on the 10th day of every month."')]),t._v(" "),a("p",[t._v("Why Jobs AND Triggers? Many job schedulers do not have separate notions of jobs and triggers. Some define a 'job' as simply an execution time (or schedule)\nalong with some small job identifier. Others are much like the union of Quartz's job and trigger objects. While developing Quartz, we decided that it made sense\nto create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits.")]),t._v(" "),a("p",[t._v("For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job.\nAnother benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired,\nso that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define\nits associated job.")]),t._v(" "),a("h2",{attrs:{id:"identities"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#identities"}},[t._v("#")]),t._v(" Identities")]),t._v(" "),a("p",[t._v('Jobs and Triggers are given identifying keys as they are registered with the Quartz scheduler.\nThe keys of Jobs and Triggers (JobKey and TriggerKey) allow them to be placed into \'groups\' which can be useful for organizing your jobs and\ntriggers into categories such as "reporting jobs" and "maintenance jobs". The name portion of the key of a job or trigger must be unique within the group')]),t._v(" "),a("ul",[a("li",[t._v("or in other words, the complete key (or identifier) of a job or trigger is the compound of the name and group.")])]),t._v(" "),a("p",[t._v("You now have a general idea about what Jobs and Triggers are, you can learn more about them in\n"),a("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/more-about-jobs.html"}},[t._v("Lesson 3: More About Jobs & JobDetails")]),t._v(" and "),a("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/more-about-triggers.html"}},[t._v("Lesson 4: More About Triggers")])],1)])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/93.e616473a.js b/assets/js/93.e616473a.js new file mode 100644 index 000000000..9a5bb7ada --- /dev/null +++ b/assets/js/93.e616473a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[93],{467:function(t,e,a){"use strict";a.r(e);var o=a(26),n=Object(o.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"plug-ins"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#plug-ins"}},[t._v("#")]),t._v(" Plug-Ins")]),t._v(" "),a("p",[t._v("Quartz provides an interface (ISchedulerPlugin) for plugging-in additional functionality.")]),t._v(" "),a("p",[t._v("Plugins that ship with Quartz to provide various utililty capabilities can be found documented in the Quartz.Plugins namespace.\nThey provide functionality such as auto-scheduling of jobs upon scheduler startup, logging a history of job and trigger events,\nand ensuring that the scheduler shuts down cleanly when the virtual machine exits.")]),t._v(" "),a("h2",{attrs:{id:"jobfactory"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jobfactory"}},[t._v("#")]),t._v(" JobFactory")]),t._v(" "),a("p",[t._v("When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler.\nThe default JobFactory simply activates a new instance of the job class. You may want to create your own implementation\nof JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.")]),t._v(" "),a("p",[t._v("See the IJobFactory interface, and the associated Scheduler.SetJobFactory(fact) method.")]),t._v(" "),a("h2",{attrs:{id:"factory-shipped-jobs"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factory-shipped-jobs"}},[t._v("#")]),t._v(" 'Factory-Shipped' Jobs")]),t._v(" "),a("p",[t._v("Quartz also provides a number of utility Jobs that you can use in your application for doing things like sending\ne-mails and invoking remote objects. These out-of-the-box Jobs can be found documented in the Quartz.Jobs namespace.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/94.8b47a217.js b/assets/js/94.8b47a217.js new file mode 100644 index 000000000..1f5b48b7f --- /dev/null +++ b/assets/js/94.8b47a217.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[94],{468:function(t,a,s){"use strict";s.r(a);var e=s(26),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("As you saw in Lesson 2, jobs are rather easy to implement. There are just a few more things that you need to understand about\nthe nature of jobs, about the Execute(..) method of the IJob interface, and about JobDetails.")]),t._v(" "),s("p",[t._v("While a job class that you implement has the code that knows how to do the actual work\nof the particular type of job, Quartz.NET needs to be informed about various attributes\nthat you may wish an instance of that job to have. This is done via the JobDetail class,\nwhich was mentioned briefly in the previous section.")]),t._v(" "),s("p",[t._v("JobDetail instances are built using the JobBuilder class. JobBuilder allows you to describe\nyour job's details using a fluent interface.")]),t._v(" "),s("p",[t._v("Let's take a moment now to discuss a bit about the 'nature' of jobs and the life-cycle of job instances within Quartz.NET.\nFirst lets take a look back at some of that snippet of code we saw in Lesson 1:")]),t._v(" "),s("p",[s("strong",[t._v("Using Quartz.NET")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then every 40 seconds")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n\t "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("40")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \nsched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("Now consider the job class "),s("strong",[t._v("HelloJob")]),t._v(" defined as such:")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HelloJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\tConsole"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"HelloJob is executing."')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Notice that we give the scheduler a IJobDetail instance, and that it refers to the job to be executed by simply\nproviding the job's class. Each (and every) time the scheduler executes the job, it creates a new instance of the\nclass before calling its Execute(..) method. One of the ramifications of this behavior is the fact that jobs must\nhave a no-arguement constructor. Another ramification is that it does not make sense to have data-fields defined\non the job class - as their values would not be preserved between job executions.")]),t._v(" "),s("p",[t._v('You may now be wanting to ask "how can I provide properties/configuration for a Job instance?" and "how can I\nkeep track of a job\'s state between executions?" The answer to these questions are the same: the key is the JobDataMap,\nwhich is part of the JobDetail object.')]),t._v(" "),s("h2",{attrs:{id:"jobdatamap"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#jobdatamap"}},[t._v("#")]),t._v(" JobDataMap")]),t._v(" "),s("p",[t._v("The JobDataMap can be used to hold any number of (serializable) objects which you wish to have made available\nto the job instance when it executes. JobDataMap is an implementation of the IDictionary interface, and has\nsome added convenience methods for storing and retrieving data of primitive types.")]),t._v(" "),s("p",[t._v("Here's some quick snippets of putting data into the JobDataMap prior to adding the job to the scheduler:")]),t._v(" "),s("p",[s("strong",[t._v("Setting Values in a JobDataMap")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our DumbJob class")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token generic-method"}},[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token generic class-name"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("DumbJob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// name "myJob", group "group1"')]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Hello World!"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("UsingJobData")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3.141f")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("Here's a quick example of getting data from the JobDataMap during the job's execution:")]),t._v(" "),s("p",[s("strong",[t._v("Getting Values from a JobDataMap")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobKey")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" myFloatValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetFloat")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t Console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" of DumbJob says: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", and val is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" myFloatValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),s("p",[t._v("If you use a persistent JobStore (discussed in the JobStore section of this tutorial) you should use some care\nin deciding what you place in the JobDataMap, because the object in it will be serialized, and they therefore\nbecome prone to class-versioning problems. Obviously standard .NET types should be very safe, but beyond that,\nany time someone changes the definition of a class for which you have serialized instances,\ncare has to be taken not to break compatibility.")]),t._v(" "),s("p",[t._v("Optionally, you can put AdoJobStore and JobDataMap into a mode where only primitives\nand strings can be stored in the map, thus eliminating any possibility of later serialization problems.")]),t._v(" "),s("p",[t._v("If you add properties with set accessor to your job class that correspond to the names of keys in the JobDataMap,\nthen Quartz's default JobFactory implementation will automatically call those setters when the job is instantiated,\nthus preventing the need to explicitly get the values out of the map within your execute method. Note this\nfunctionality is not maintained by default when using a custom JobFactory.")]),t._v(" "),s("p",[t._v("Triggers can also have JobDataMaps associated with them. This can be useful in the case where you have a Job that is stored in the scheduler\nfor regular/repeated use by multiple Triggers, yet with each independent triggering, you want to supply the Job with different data inputs.")]),t._v(" "),s("p",[t._v("The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge of the JobDataMap\nfound on the JobDetail and the one found on the Trigger, with the values in the latter overriding any same-named values in the former.")]),t._v(" "),s("p",[t._v("Here's a quick example of getting data from the JobExecutionContext's merged JobDataMap during the job's execution:")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobKey")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MergedJobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note the difference from the previous example")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"jobSays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" myFloatValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetFloat")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myFloatValue"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" state "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("IList"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myStateData"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\tstate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\tConsole"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" of DumbJob says: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" jobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", and val is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" myFloatValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v('Or if you wish to rely on the JobFactory "injecting" the data map values onto your class, it might look like this instead:')]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DumbJob")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-list"}},[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJob")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" JobSays "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("float")])]),t._v(" FloatValue "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n \n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Execute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobKey")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("JobDetail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobDataMap")]),t._v(" dataMap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("MergedJobDataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note the difference from the previous example")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" state "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("IList"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" dataMap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myStateData"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\tstate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateTimeOffset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("UtcNow"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\tConsole"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WriteLine")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Instance "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" of DumbJob says: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" JobSays "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", and val is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" FloatValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("You'll notice that the overall code of the class is longer, but the code in the Execute() method is cleaner.\nOne could also argue that although the code is longer, that it actually took less coding, if the programmer's IDE was used to auto-generate the properties,\nrather than having to hand-code the individual calls to retrieve the values from the JobDataMap. The choice is yours.")]),t._v(" "),s("h2",{attrs:{id:"job-instances"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#job-instances"}},[t._v("#")]),t._v(' Job "Instances"')]),t._v(" "),s("p",[t._v('Many users spend time being confused about what exactly constitutes a "job instance".\nWe\'ll try to clear that up here and in the section below about job state and concurrency.')]),t._v(" "),s("p",[t._v("You can create a single job class, and store many 'instance definitions' of it within the scheduler by creating multiple instances of JobDetails")]),t._v(" "),s("ul",[s("li",[t._v("each with its own set of properties and JobDataMap - and adding them all to the scheduler.")])]),t._v(" "),s("p",[t._v('For example, you can create a class that implements the IJob interface called "SalesReportJob".\nThe job might be coded to expect parameters sent to it (via the JobDataMap) to specify the name of the sales person that the sales\nreport should be based on. They may then create multiple definitions (JobDetails) of the job, such as "SalesReportForJoe"\nand "SalesReportForMike" which have "joe" and "mike" specified in the corresponding JobDataMaps as input to the respective jobs.')]),t._v(" "),s("p",[t._v("When a trigger fires, the JobDetail (instance definition) it is associated to is loaded,\nand the job class it refers to is instantiated via the JobFactory configured on the Scheduler.\nThe default JobFactory simply calls the default constructor of the job class using Activator.CreateInstance,\nthen attempts to call setter properties on the class that match the names of keys within the JobDataMap.\nYou may want to create your own implementation of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.")]),t._v(" "),s("p",[t._v('In "Quartz speak", we refer to each stored JobDetail as a "job definition" or "JobDetail instance",\nand we refer to a each executing job as a "job instance" or "instance of a job definition".\nUsually if we just use the word "job" we are referring to a named definition, or JobDetail.\nWhen we are referring to the class implementing the job interface, we usually use the term "job type".')]),t._v(" "),s("h2",{attrs:{id:"job-state-and-concurrency"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#job-state-and-concurrency"}},[t._v("#")]),t._v(" Job State and Concurrency")]),t._v(" "),s("p",[t._v("Now, some additional notes about a job's state data (aka JobDataMap) and concurrency.\nThere are a couple attributes that can be added to your Job class that affect Quartz's behaviour with respect to these aspects.")]),t._v(" "),s("p",[s("strong",[t._v("DisallowConcurrentExecution")]),t._v(' is an attribute that can be added to the Job class that tells Quartz not to execute multiple instances\nof a given job definition (that refers to the given job class) concurrently.\nNotice the wording there, as it was chosen very carefully. In the example from the previous section, if "SalesReportJob" has this attribute,\nthan only one instance of "SalesReportForJoe" can execute at a given time, but it can execute concurrently with an instance of "SalesReportForMike".\nThe constraint is based upon an instance definition (JobDetail), not on instances of the job class.\nHowever, it was decided (during the design of Quartz) to have the attribute carried on the class itself, because it does often make a difference to how the class is coded.')]),t._v(" "),s("p",[s("strong",[t._v("PersistJobDataAfterExecution")]),t._v(" is an attribute that can be added to the Job class that tells Quartz to update the stored copy of\nthe JobDetail's JobDataMap after the Execute() method completes successfully (without throwing an exception), such that the next\nexecution of the same job (JobDetail) receives the updated values rather than the originally stored values.\nLike the "),s("strong",[t._v("DisallowConcurrentExecution")]),t._v(" attribute, this applies to a job definition instance, not a job class instance,\nthough it was decided to have the job class carry the attribute because it does often make a difference to how the class is coded\n(e.g. the 'statefulness' will need to be explicitly 'understood' by the code within the execute method).")]),t._v(" "),s("p",[t._v("If you use the "),s("strong",[t._v("PersistJobDataAfterExecution")]),t._v(" attribute, you should strongly consider also using the "),s("strong",[t._v("DisallowConcurrentExecution")]),t._v(" attribute,\nin order to avoid possible confusion (race conditions) of what data was left stored when two instances of the same job (JobDetail) executed concurrently.")]),t._v(" "),s("h2",{attrs:{id:"other-attributes-of-jobs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#other-attributes-of-jobs"}},[t._v("#")]),t._v(" Other Attributes Of Jobs")]),t._v(" "),s("p",[t._v("Here's a quick summary of the other properties which can be defined for a job instance via the JobDetail object:")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("Durability")]),t._v(" - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it.\nIn other words, non-durable jobs have a life span bounded by the existence of its triggers.")]),t._v(" "),s("li",[s("strong",[t._v("RequestsRecovery")]),t._v(" - if a job \"requests recovery\", and it is executing during the time of a 'hard shutdown' of the scheduler\n(i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again.\nIn this case, the JobExecutionContext.Recovering property will return true.")])]),t._v(" "),s("h2",{attrs:{id:"jobexecutionexception"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#jobexecutionexception"}},[t._v("#")]),t._v(" JobExecutionException")]),t._v(" "),s("p",[t._v("Finally, we need to inform you of a few details of the IJob.Execute(..) method. The only type of exception\nthat you should throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire contents of the\nexecute method with a 'try-catch' block. You should also spend some time looking at the documentation for the JobExecutionException,\nas your job can use it to provide the scheduler various directives as to how you want the exception to be handled.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/95.487cae6e.js b/assets/js/95.487cae6e.js new file mode 100644 index 000000000..097a5ac42 --- /dev/null +++ b/assets/js/95.487cae6e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[95],{469:function(t,e,s){"use strict";s.r(e);var a=s(26),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("p",[t._v("Like jobs, triggers are relatively easy to work with, but do contain a variety of customizable options that you need to\nbe aware of and understand before you can make full use of Quartz.NET. Also, as noted earlier, there are different types of triggers,\nthat you can select to meet different scheduling needs.")]),t._v(" "),s("h2",{attrs:{id:"common-trigger-attributes"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#common-trigger-attributes"}},[t._v("#")]),t._v(" Common Trigger Attributes")]),t._v(" "),s("p",[t._v("Aside from the fact that all trigger types have TriggerKey properties for tracking their identities,\nthere are a number of other properties that are common to all trigger types. These common properties are set using the TriggerBuilder\nwhen you are building the trigger definition (examples of that will follow).")]),t._v(" "),s("p",[t._v("Here is a listing of properties common to all trigger types:")]),t._v(" "),s("ul",[s("li",[t._v("The "),s("strong",[t._v("JobKey")]),t._v(" property indicates the identity of the job that should be executed when the trigger fires.")]),t._v(" "),s("li",[t._v("The "),s("strong",[t._v("StartTimeUtc")]),t._v(' property indicates when the trigger\'s schedule first comes into affect.\nThe value is a DateTimeOffset object that defines a moment in time on a given calendar date.\nFor some trigger types, the trigger will actually fire at the start time, for others it simply marks the time that the schedule should start being followed.\nThis means you can store a trigger with a schedule such as "every 5th day of the month" during January, and if the StartTimeUtc property is set to April 1st,\nit will be a few months before the first firing.')]),t._v(" "),s("li",[t._v("The "),s("strong",[t._v("EndTimeUtc")]),t._v(" property indicates when the trigger's schedule should no longer be in effect.\nIn other words, a trigger with a schedule of \"every 5th day of the month\" and with an end time of July 1st will fire for it's last time on June 5th.")])]),t._v(" "),s("p",[t._v("Other properties, which take a bit more explanation are discussed in the following sub-sections.")]),t._v(" "),s("h2",{attrs:{id:"priority"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#priority"}},[t._v("#")]),t._v(" Priority")]),t._v(" "),s("p",[t._v("Sometimes, when you have many Triggers (or few worker threads in your Quartz.NET thread pool), Quartz.NET may not have enough resources to immediately fire all\nof the Triggers that are scheduled to fire at the same time. In this case, you may want to control which of your Triggers get first crack at the available Quartz.NET worker threads.\nFor this purpose, you can set the priority property on a Trigger. If N Triggers are to fire at the same time, but there are only Z worker threads currently available,\nthen the first Z Triggers with the highest priority will be executed first. If you do not set a priority on a Trigger, then it will use the default priority of 5.\nAny integer value is allowed for priority, positive or negative.")]),t._v(" "),s("p",[s("strong",[t._v("Note:")]),t._v(" Priorities are only compared when triggers have the same fire time. A trigger scheduled to fire at 10:59 will always fire before one scheduled to fire at 11:00.")]),t._v(" "),s("p",[s("strong",[t._v("Note:")]),t._v(" When a trigger's job is detected to require recovery, its recovery is scheduled with the same priority as the original trigger.")]),t._v(" "),s("h2",{attrs:{id:"misfire-instructions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#misfire-instructions"}},[t._v("#")]),t._v(" Misfire Instructions")]),t._v(" "),s("p",[t._v('Another important property of a Trigger is its "misfire instruction". A misfire occurs if a persistent trigger "misses" its firing time because of the scheduler being shutdown,\nor because there are no available threads in Quartz.NET\'s thread pool for executing the job.\nThe different trigger types have different misfire instructions available to them.\nBy default they use a \'smart policy\' instruction - which has dynamic behavior based on trigger type and configuration.\nWhen the scheduler starts, it searches for any persistent triggers that have misfired, and it then updates each of them based on their individually\nconfigured misfire instructions. When you start using Quartz.NET in your own projects, you should make yourself familiar with the misfire instructions\nthat are defined on the given trigger types, and explained in their API documentation. More specific information about misfire instructions will be given within\nthe tutorial lessons specific to each trigger type.')]),t._v(" "),s("h2",{attrs:{id:"calendars"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#calendars"}},[t._v("#")]),t._v(" Calendars")]),t._v(" "),s("p",[t._v("Quartz.NET Calendar objects implementing ICalendar interface can be associated with triggers at the time the trigger is stored in the scheduler.\nCalendars are useful for excluding blocks of time from the the trigger's firing schedule. For instance, you could\ncreate a trigger that fires a job every weekday at 9:30 am, but then add a Calendar that excludes all of the business's holidays.")]),t._v(" "),s("p",[t._v("Calendar's can be any serializable objects that implement the ICalendar interface, which looks like this:")]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("namespace")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("Quartz")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ICalendar")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Description "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("ICalendar")]),t._v(" CalendarBase "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("IsTimeIncluded")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DateTimeOffset")]),t._v(" timeUtc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),s("span",{pre:!0,attrs:{class:"token return-type class-name"}},[t._v("DateTime")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetNextIncludedTimeUtc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DateTimeOffset")]),t._v(" timeUtc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),s("p",[t._v("Even though calendars can 'block out' sections of time as narrow as a millisecond, most likely, you'll be interested in\n'blocking-out' entire days. As a convenience, Quartz.NET includes the class HolidayCalendar, which does just that.")]),t._v(" "),s("p",[t._v("Calendars must be instantiated and registered with the scheduler via the AddCalendar(..) method. If you use HolidayCalendar,\nafter instantiating it, you should use its AddExcludedDate(DateTime date) method in order to populate it with the days you wish\nto have excluded from scheduling. The same calendar instance can be used with multiple triggers such as this:")]),t._v(" "),s("p",[s("strong",[t._v("Calendar Example")])]),t._v(" "),s("div",{staticClass:"language-csharp extra-class"},[s("pre",{pre:!0,attrs:{class:"language-csharp"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HolidayCalendar")]),t._v(" cal "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("HolidayCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n cal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddExcludedDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("someDate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n sched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" t "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DailyAtHourAndMinute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// execute job daily at 9:30")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ModifiedByCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// but not on holidays")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. schedule job with trigger")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" t2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSchedule")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("CronScheduleBuilder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DailyAtHourAndMinute")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// execute job daily at 11:30")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ModifiedByCalendar")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myHolidays"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// but not on holidays")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. schedule job with trigger2 ")]),t._v("\n")])])]),s("p",[t._v("The details of the construction/building of triggers will be given in the next couple lessons.\nFor now, just believe that the code above creates two triggers, each scheduled to fire daily.\nHowever, any of the firings that would have occurred during the period excluded by the calendar will be skipped.")]),t._v(" "),s("p",[t._v("See the Quartz.Impl.Calendar namespace for a number of ICalendar implementations that may suit your needs.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/96.848a034e.js b/assets/js/96.848a034e.js new file mode 100644 index 000000000..7ca37a4c7 --- /dev/null +++ b/assets/js/96.848a034e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[96],{470:function(s,t,a){"use strict";a.r(t);var e=a(26),n=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("p",[s._v("SchedulerListeners are much like ITriggerListeners and IJobListeners, except they receive notification of\nevents within the scheduler itself - not necessarily events related to a specific trigger or job.")]),s._v(" "),a("p",[s._v("Scheduler-related events include: the addition of a job/trigger, the removal of a job/trigger, a serious error\nwithin the scheduler, notification of the scheduler being shutdown, and others.")]),s._v(" "),a("p",[a("strong",[s._v("The ISchedulerListener Interface")])]),s._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("interface")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("ISchedulerListener")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobScheduled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Trigger")]),s._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobUnscheduled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggerFinalized")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Trigger")]),s._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggersPaused")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("TriggersResumed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" triggerGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobsPaused")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("JobsResumed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" jobGroup"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("SchedulerError")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("string")])]),s._v(" msg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("SchedulerException")]),s._v(" cause"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("SchedulerShutdown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" \n")])])]),a("p",[s._v("SchedulerListeners are registered with the scheduler's ListenerManager.\nSchedulerListeners can be virtually any object that implements the ISchedulerListener interface.")]),s._v(" "),a("p",[a("strong",[s._v("Adding a SchedulerListener:")])]),s._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[s._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("AddSchedulerListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("mySchedListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])])]),a("p",[a("strong",[s._v("Removing a SchedulerListener:")])]),s._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[s._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("RemoveSchedulerListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("mySchedListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/97.d11e3968.js b/assets/js/97.d11e3968.js new file mode 100644 index 000000000..952ef5092 --- /dev/null +++ b/assets/js/97.d11e3968.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[97],{471:function(t,s,n){"use strict";n.r(s);var a=n(26),e=Object(a.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[t._v("SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time,\nor at a specific moment in time followed by repeats at a specific interval. Or plainer english, if you want the trigger to\nfire at exactly 11:23:54 AM on January 13, 2005, and then fire five more times, every ten seconds.")]),t._v(" "),n("p",[t._v("With this description, you may not find it surprising to find that the properties of a SimpleTrigger include: a start-time,\nand end-time, a repeat count, and a repeat interval. All of these properties are exactly what you'd expect them to be, with\nonly a couple special notes related to the end-time property.")]),t._v(" "),n("p",[t._v("The repeat count can be zero, a positive integer, or the constant value SimpleTrigger.RepeatIndefinitely.\nThe repeat interval property must be TimeSpan.Zero, or a positive TimeSpan value.\nNote that a repeat interval of zero will cause 'repeat count' firings of the trigger to happen concurrently\n(or as close to concurrently as the scheduler can manage).")]),t._v(" "),n("p",[t._v("If you're not already familiar with the DateTime class, you may find it helpful for computing your trigger fire-times,\ndepending on the startTimeUtc (or endTimeUtc) that you're trying to create.")]),t._v(" "),n("p",[t._v("The EndTimeUtc property (if it is specified) over-rides the repeat count property. This can be useful if you wish to create a trigger\nsuch as one that fires every 10 seconds until a given moment in time - rather than having to compute the number of times it would\nrepeat between the start-time and the end-time, you can simply specify the end-time and then use a repeat count of RepeatIndefinitely\n(you could even specify a repeat count of some huge number that is sure to be more than the number of times the trigger will actually\nfire before the end-time arrives).")]),t._v(" "),n("p",[t._v("SimpleTrigger instances are built using "),n("strong",[t._v("TriggerBuilder")]),t._v(" (for the trigger's main properties) and "),n("strong",[t._v("WithSimpleSchedule")]),t._v(" extension method (for the SimpleTrigger-specific properties).")]),t._v(" "),n("p",[n("strong",[t._v("Build a trigger for a specific moment in time, with no repeats:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// trigger builder creates simple trigger by default, actually an ITrigger is returned")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISimpleTrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ISimpleTrigger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myStartTime"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// some Date ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"job1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// identify job with name, group strings")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger for a specific moment in time, then repeating every ten seconds ten times:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger3"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myTimeToStartFiring"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// if a start time is not given (if this line were omitted), "now" is implied')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithRepeatCount")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// note that 10 repeats will give a total of 11 firings")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// identify job with handle to its JobDetail itself ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire once, five minutes in the future:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ISimpleTrigger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger5"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("FutureDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" IntervalUnit"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Minute"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// use DateBuilder to create a date in the future")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ForJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobKey"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// identify job with its JobKey")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire now, then repeat every five minutes, until the hour 22:00:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger7"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInMinutes")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("EndAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("DateOf")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[n("strong",[t._v("Build a trigger that will fire at the top of the next hour, then repeat every 2 hours, forever:")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger8"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// because group is not specified, "trigger8" will be in the default group')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartAt")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("DateBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("EvenHourDate")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// get the next even-hour (minutes and seconds zero ("00:00"))')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInHours")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// note that in this example, 'forJob(..)' is not called ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// - which is valid if the trigger is passed to the scheduler along with the job ")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nscheduler"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("scheduleJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("trigger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" job"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("Spend some time looking at all of the available methods in the language defined by "),n("strong",[t._v("TriggerBuilder")]),t._v(" and its extension method "),n("strong",[t._v("WithSimpleSchedule")]),t._v(" so that you can be familiar with options available to you that may not have been demonstrated in the examples above.")]),t._v(" "),n("h2",{attrs:{id:"simpletrigger-misfire-instructions"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#simpletrigger-misfire-instructions"}},[t._v("#")]),t._v(" SimpleTrigger Misfire Instructions")]),t._v(" "),n("p",[t._v("SimpleTrigger has several instructions that can be used to inform Quartz.NET what it should do when a misfire occurs.\n(Misfire situations were introduced in the More About Triggers section of this tutorial).\nThese instructions are defined as constants on MisfirePolicy.SimpleTrigger (including API documentation describing their behavior).\nThe instructions include:")]),t._v(" "),n("p",[n("strong",[t._v("Misfire Instruction Constants for SimpleTrigger")])]),t._v(" "),n("ul",[n("li",[t._v("MisfireInstruction.IgnoreMisfirePolicy")]),t._v(" "),n("li",[t._v("MisfirePolicy.SimpleTrigger.FireNow")]),t._v(" "),n("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNowWithExistingRepeatCount")]),t._v(" "),n("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNowWithRemainingRepeatCount")]),t._v(" "),n("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNextWithRemainingCount")]),t._v(" "),n("li",[t._v("MisfirePolicy.SimpleTrigger.RescheduleNextWithExistingCount")])]),t._v(" "),n("p",[t._v("You should recall from the earlier lessons that all triggers have the MisfirePolicy.SmartPolicy instruction available for use,\nand this instruction is also the default for all trigger types.")]),t._v(" "),n("p",[t._v("If the 'smart policy' instruction is used, SimpleTrigger dynamically chooses between its various MISFIRE instructions, based on the configuration\nand state of the given SimpleTrigger instance. The documentation for the SimpleTrigger.UpdateAfterMisfire() method explains the exact details of\nthis dynamic behavior.")]),t._v(" "),n("p",[t._v("When building SimpleTriggers, you specify the misfire instruction as part of the simple schedule (via SimpleSchedulerBuilder):")]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v("trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger7"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInMinutes")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithMisfireHandlingInstructionNextWithExistingCount")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/98.1252ce69.js b/assets/js/98.1252ce69.js new file mode 100644 index 000000000..9feead0aa --- /dev/null +++ b/assets/js/98.1252ce69.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[98],{472:function(t,s,a){"use strict";a.r(s);var e=a(26),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("Listeners are objects that you create to perform actions based on events occuring within the scheduler.\nAs you can probably guess, TriggerListeners receive events related to triggers, and JobListeners receive events related to jobs.")]),t._v(" "),a("p",[t._v('Trigger-related events include: trigger firings, trigger mis-firings (discussed in the "Triggers" section of this document),\nand trigger completions (the jobs fired off by the trigger is finished).')]),t._v(" "),a("p",[a("strong",[t._v("The ITriggerListener Interface")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITriggerListener")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerFired")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("VetoJobExecution")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerMisfired")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t \n\t "),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("TriggerComplete")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")])]),t._v(" triggerInstructionCode"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Job-related events include: a notification that the job is about to be executed, and a notification when the job has completed execution.")]),t._v(" "),a("p",[a("strong",[t._v("The IJobListener Interface")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobListener")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("string")])]),t._v(" Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobToBeExecuted")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobExecutionVetoed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token return-type class-name"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("JobWasExecuted")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobExecutionContext")]),t._v(" context"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JobExecutionException")]),t._v(" jobException"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),a("h2",{attrs:{id:"using-your-own-listeners"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-your-own-listeners"}},[t._v("#")]),t._v(" Using Your Own Listeners")]),t._v(" "),a("p",[t._v("To create a listener, simply create an object the implements either the ITriggerListener and/or IJobListener interface.\nListeners are then registered with the scheduler during run time, and must be given a name (or rather, they must advertise their own\nname via their Name property.")]),t._v(" "),a("p",[t._v("For your convenience, rather than implementing those interfaces, your class could also extend the class JobListenerSupport or TriggerListenerSupport\nand simply override the events you're interested in.")]),t._v(" "),a("p",[t._v("Listeners are registered with the scheduler's ListenerManager along with a Matcher that describes which Jobs/Triggers the listener wants to receive events for.")]),t._v(" "),a("p",[a("em",[t._v("Listeners are registered with the scheduler during run time, and are NOT stored in the JobStore along with the jobs and triggers.\nThis is because listeners are typically an integration point with your application.\nHence, each time your application runs, the listeners need to be re-registered with the scheduler.")])]),t._v(" "),a("p",[a("strong",[t._v("Adding a JobListener that is interested in a particular job:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" KeyMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("KeyEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("JobKey")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobName"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Adding a JobListener that is interested in all jobs of a particular group:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GroupEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Adding a JobListener that is interested in all jobs of two particular groups:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tOrMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Or")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GroupEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJobGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("GroupEquals")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"yourGroup"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[a("strong",[t._v("Adding a JobListener that is interested in all jobs:")])]),t._v(" "),a("div",{staticClass:"language-csharp extra-class"},[a("pre",{pre:!0,attrs:{class:"language-csharp"}},[a("code",[t._v("scheduler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ListenerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AddJobListener")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myJobListener"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GroupMatcher"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("JobKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("AnyGroup")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Listeners are not used by most users of Quartz.NET, but are handy when application requirements create the need\nfor the notification of events, without the Job itself explicitly notifying the application.")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/99.f28f8a22.js b/assets/js/99.f28f8a22.js new file mode 100644 index 000000000..9d668ccc8 --- /dev/null +++ b/assets/js/99.f28f8a22.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[99],{473:function(t,s,n){"use strict";n.r(s);var a=n(26),e=Object(a.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[t._v("Before you can use the scheduler, it needs to be instantiated (who'd have guessed?).\nTo do this, you use an implementor of ISchedulerFactory.")]),t._v(" "),n("p",[t._v("Once a scheduler is instantiated, it can be started, placed in stand-by mode, and shutdown.\nNote that once a scheduler is shutdown, it cannot be restarted without being re-instantiated.\nTriggers do not fire (jobs do not execute) until the scheduler has been started, nor while it is\nin the paused state.")]),t._v(" "),n("p",[t._v("Here's a quick snippet of code, that instantiates and starts a scheduler, and schedules a job for execution:")]),t._v(" "),n("p",[n("strong",[t._v("Using Quartz.NET")])]),t._v(" "),n("div",{staticClass:"language-csharp extra-class"},[n("pre",{pre:!0,attrs:{class:"language-csharp"}},[n("code",[t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// construct a scheduler factory")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ISchedulerFactory")]),t._v(" schedFact "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constructor-invocation class-name"}},[t._v("StdSchedulerFactory")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get a scheduler")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IScheduler")]),t._v(" sched "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" schedFact"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("GetScheduler")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n sched"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Start")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n\t"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// define the job and tie it to our HelloJob class")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IJobDetail")]),t._v(" job "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" JobBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token generic-method"}},[n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token generic class-name"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("HelloJob"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myJob"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Trigger the job to run now, and then every 40 seconds")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ITrigger")]),t._v(" trigger "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TriggerBuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Create")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIdentity")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"myTrigger"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"group1"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("StartNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithSimpleSchedule")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" x\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("WithIntervalInSeconds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("40")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("RepeatForever")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t \n sched"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ScheduleJob")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("job"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trigger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("As you can see, working with Quartz.NET is rather simple. In "),n("RouterLink",{attrs:{to:"/documentation/quartz-2.x/tutorial/jobs-and-triggers.html"}},[t._v("Lesson 2")]),t._v(" we'll give a quick overview of Jobs and Triggers, so that you can more fully understand this example.")],1)])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/app.78225083.js b/assets/js/app.78225083.js new file mode 100644 index 000000000..e28294908 --- /dev/null +++ b/assets/js/app.78225083.js @@ -0,0 +1,8 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,i,u=e[0],s=e[1],l=e[2],f=0,d=[];f=n.length?{value:void 0,done:!0}:(t=r(n,a),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r=n(6),a=n(8),o=n(33);t.exports=r?function(t,e,n){return a.f(t,e,o(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(57),a=Math.min;t.exports=function(t){return t>0?a(r(t),9007199254740991):0}},function(t,e,n){var r=n(37),a=n(21);t.exports=function(t){return r(a(t))}},function(t,e,n){var r=n(3),a=n(131),o=n(102),i=n(13),u=n(2),s=u("iterator"),l=u("toStringTag"),c=o.values;for(var f in a){var d=r[f],p=d&&d.prototype;if(p){if(p[s]!==c)try{i(p,s,c)}catch(t){p[s]=c}if(p[l]||i(p,l,f),a[f])for(var h in o)if(p[h]!==o[h])try{i(p,h,o[h])}catch(t){p[h]=o[h]}}}},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){var r=n(142),a="object"==typeof self&&self&&self.Object===Object&&self,o=r||a||Function("return this")();t.exports=o},function(t,e,n){var r=n(112),a=n(3),o=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?o(r[t])||o(a[t]):r[t]&&r[t][e]||a[t]&&a[t][e]}},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e){t.exports=!1},function(t,e,n){var r=n(6),a=n(83),o=n(33),i=n(15),u=n(38),s=n(7),l=n(111),c=Object.getOwnPropertyDescriptor;e.f=r?c:function(t,e){if(t=i(t),e=u(e,!0),l)try{return c(t,e)}catch(t){}if(s(t,e))return o(!a.f.call(t,e),t[e])}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(232),a=n(235);t.exports=function(t,e){var n=a(t,e);return r(n)?n:void 0}},function(t,e,n){"use strict";function r(t,e,n,r,a,o,i,u){var s,l="function"==typeof t?t.options:t;if(e&&(l.render=e,l.staticRenderFns=n,l._compiled=!0),r&&(l.functional=!0),o&&(l._scopeId="data-v-"+o),i?(s=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),a&&a.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(i)},l._ssrRegister=s):a&&(s=u?function(){a.call(this,(l.functional?this.parent:this).$root.$options.shadowRoot)}:a),s)if(l.functional){l._injectStyles=s;var c=l.render;l.render=function(t,e){return s.call(e),c(t,e)}}else{var f=l.beforeCreate;l.beforeCreate=f?[].concat(f,s):[s]}return{exports:t,options:l}}n.d(e,"a",(function(){return r}))},function(t,e,n){"use strict";var r=n(0),a=n(34).filter;r({target:"Array",proto:!0,forced:!n(60)("filter")},{filter:function(t){return a(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,e,n){var r,a=n(5),o=n(171),i=n(81),u=n(41),s=n(116),l=n(77),c=n(58),f=c("IE_PROTO"),d=function(){},p=function(t){return" + + + + + + + + + + + + +

+ + + diff --git a/blog.html b/blog.html new file mode 100644 index 000000000..a064300f0 --- /dev/null +++ b/blog.html @@ -0,0 +1,55 @@ + + + + + + Blog | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Blog

+ + + diff --git a/blogpage/2/index.html b/blogpage/2/index.html new file mode 100644 index 000000000..ce8eaedf5 --- /dev/null +++ b/blogpage/2/index.html @@ -0,0 +1,55 @@ + + + + + + Page 2 | Post | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blogpage/3/index.html b/blogpage/3/index.html new file mode 100644 index 000000000..37e6ab758 --- /dev/null +++ b/blogpage/3/index.html @@ -0,0 +1,55 @@ + + + + + + Page 3 | Post | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blogpage/4/index.html b/blogpage/4/index.html new file mode 100644 index 000000000..0faa06cef --- /dev/null +++ b/blogpage/4/index.html @@ -0,0 +1,55 @@ + + + + + + Page 4 | Post | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blogpage/5/index.html b/blogpage/5/index.html new file mode 100644 index 000000000..534d941d4 --- /dev/null +++ b/blogpage/5/index.html @@ -0,0 +1,55 @@ + + + + + + Page 5 | Post | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browserconfig.xml b/browserconfig.xml new file mode 100644 index 000000000..c55414822 --- /dev/null +++ b/browserconfig.xml @@ -0,0 +1,2 @@ + +#ffffff \ No newline at end of file diff --git a/documentation/best-practices.html b/documentation/best-practices.html new file mode 100644 index 000000000..e4bba3878 --- /dev/null +++ b/documentation/best-practices.html @@ -0,0 +1,71 @@ + + + + + + Best Practices | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This document was adapted from Quartz Java

# JobDataMap Tips

# Only Store Primitive Data Types (including Strings) In the JobDataMap

Only store primitive data types (including strings) in JobDataMap to avoid data serialization issues short and long-term.

# Use the Merged JobDataMap

The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. +It is a merge of the JobDataMap found on the JobDetail and the one found on the Trigger, with the value in the latter overriding any same-named values in the former.

Storing JobDataMap values on a Trigger can be useful in the case where you have a Job that is stored in the scheduler for regular/repeated use by multiple Triggers, +yet with each independent triggering, you want to supply the Job with different data inputs.

In light of all of the above, we recommend as a best practice the following: Code within the IJob.Execute(..) method should generally retrieve +values from the JobDataMap on found on the JobExecutionContext, rather than directly from the one on the JobDetail.

# Trigger Tips

# Use TriggerUtils

TriggerUtils:

  • Offers a simple way to create Dates (for start/end dates)
  • Offers helpers for analyzing triggers (e.g. calculating future fire times)

# ADO.NET JobStore

# Never Write Directly To Quartz's Tables

Writing scheduling data directly to the database (via SQL) rather than using scheduling API:

  • Results in data corruption (deleted data, scrambled data)
  • Results in job seemingly "vanishing" without executing when a trigger's fire time arrives
  • Results in job not executing "just sitting there" when a trigger's fire time arrives
  • May result in: Dead-locks
  • Other strange problems and data corruption

# Never Point A Non-Clustered Scheduler At the Same Database As Another Scheduler With The Same Scheduler Name

If you point more than one scheduler instance at the same set of database tables, and one or more of those instances is not configured for clustering, any of the following may occur:

  • Results in data corruption (deleted data, scrambled data)
  • Results in job seemingly "vanishing" without executing when a trigger's fire time arrives
  • Results in job not executing, "just sitting there" when a trigger's fire time arrives
  • May result in: Dead-locks
  • Other strange problems and data corruption

# Ensure Adequate Datasource Connection Size

It is recommended that your Datasource max connection size be configured to be at least the number of worker threads in the thread pool plus three. +You may need additional connections if your application is also making frequent calls to the scheduler API.

# Daylight Savings Time

# Avoid Scheduling Jobs Near the Transition Hours of Daylight Savings Time

NOTE: Specifics of the transition hour and the amount of time the clock moves forward or back varies by locale see: https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world (opens new window).

SimpleTriggers are not affected by Daylight Savings Time as they always fire at an exact millisecond in time, and repeat an exact number of milliseconds apart.

Because CronTriggers fire at given hours/minutes/seconds, they are subject to some oddities when DST transitions occur.

As an example of possible issues, scheduling in the United States within TimeZones/locations that observe Daylight Savings time, the following problems may occur if using CronTrigger and scheduling fire times during the hours of 1:00 AM and 2:00 AM:

  • 1:05 AM may occur twice! - duplicate firings on CronTrigger possible
  • 2:05 AM may never occur! - missed firings on CronTrigger possible

Again, specifics of time and amount of adjustment varies by locale.

Other trigger types that are based on sliding along a calendar (rather than exact amounts of time), such as CalenderIntervalTrigger, will be similarly affected - but rather than missing a firing, or firing twice, may end up having it's fire time shifted by an hour.

# Jobs

# Waiting For Conditions

Long-running jobs prevent others from running (if all threads in the ThreadPool are busy).

If you feel the need to call Thread.sleep() on the worker thread executing the Job, it is typically a sign that the job is not ready to do the rest of its work because it needs to wait for some condition (such as the availability of a data record) to become true.

A better solution is to release the worker thread (exit the job) and allow other jobs to execute on that thread. The job can reschedule itself, or other jobs before it exits.

# Throwing Exceptions

A Job's execute method should contain a try-catch block that handles all possible exceptions.

If a job throws an exception, Quartz will typically immediately re-execute it, meaning the job can and likely will throw the same exception again. This can lead to wasted resources and, in the worst cases, unstable or crashed applications. +It's better if the job catches all exceptions it may encounter, handles them, and reschedules itself or other jobs to work around the issue.

# Recoverability and Idempotence

In-progress Jobs marked "recoverable" are automatically re-executed after a scheduler fails. This means some of the job's "work" will be executed twice.

This means the job should be coded in such a way that its work is idempotent.

# Listeners (TriggerListener, JobListener, SchedulerListener)

# Keep Code In Listeners Concise And Efficient

Performing large amounts of work is discouraged, as the thread that would be executing the job (or completing the trigger and moving on to firing another job, etc.) will be tied up within the listener.

# Handle Exceptions

Every listener method should contain a try-catch block that handles all possible exceptions.

If a listener throws an exception, it may cause other listeners not to be notified and/or prevent the execution of the job, etc.

# Exposing Scheduler Functionality Through Applications

# Be Careful of Security!

Some users expose Quartz's Scheduler functionality through an application user interface. This can be very useful, though it can also be extremely dangerous.

Be sure you don't mistakenly allow users to define jobs of any type they wish, with whatever parameters they wish. +For example, Quartz.Jobs package ships with a pre-made job NativeJob, which will execute any arbitrary native (operating system) system command that it is defined to. +Malicious users could use this to take control of, or destroy your system.

Likewise other jobs such as SendEmailJob, and virtually any others could be used for malicious intent.

Allowing users to define whatever job they want effectively opens your system to all sorts of vulnerabilities comparable/equivalent to Command Injection Attacks as defined by OWASP and MITRE.

+ + + diff --git a/documentation/faq.html b/documentation/faq.html new file mode 100644 index 000000000..15a871151 --- /dev/null +++ b/documentation/faq.html @@ -0,0 +1,187 @@ + + + + + + Frequently Asked Questions | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

TIP

This FAQ was adapted from Quartz Java

# General Questions

# What is Quartz

Quartz is a job scheduling system that can be integrated with, or used along +side virtually any other software system. The term "job scheduler" seems to +conjure different ideas for different people. As you read this tutorial, you +should be able to get a firm idea of what we mean when we use this term, but +in short, a job scheduler is a system that is responsible for executing +(or notifying) other software components when a pre-determined (scheduled) +time arrives.

Quartz is quite flexible, and contains multiple usage paradigms that can be +used separately or together, in order to achieve your desired behavior, and +enable you to write your code in the manner that seems most 'natural' to +your project.

Quartz is very light-weight, and requires very little setup/configuration - +it can actually be used 'out-of-the-box' if your needs are relatively basic.

Quartz is fault-tolerant, and can persist ('remember') your scheduled +jobs between system restarts.

Although Quartz is extremely useful for simply running certain system +processes on given schedules, the full potential of Quartz can be realized +when you learn how to use it to drive the flow of your application's +business processes.

# What is Quartz - From a Software Component View?

Quartz is distributed as a small dynamically linked library (.dll file) +that contains all of the core Quartz functionality. The main interface (API) to this +functionality is the Scheduler interface. It provides simple operations +such as scheduling/unscheduling jobs, starting/stopping/pausing the scheduler.

If you wish to schedule your own software components for execution they must +implement the simple Job interface, which contains the method execute(). +If you wish to have components notified when a scheduled fire-time arrives, +then the components should implement either the TriggerListener or JobListener +interface.

The main Quartz 'process' can be started and ran within your own application, +or a stand-alone application (with an remote interface).

# Why not just use System.Timers.Timer?

.NET Framework has "built-in" timer capabilities, through the +System.Timers.Timer class - why would someone use Quartz rather than these +standard features?

There are many reasons! Here are a few:

  • Timers have no persistence mechanism.
  • Timers have inflexible scheduling (only able to set start-time & repeat interval, nothing based on dates, time of day, etc.
  • Timers don't utilize a thread-pool (one thread per timer)
  • Timers have no real management schemes - you'd have to write your own mechanism for being able to remember, organize and retreive your tasks by name, etc.

...of course to some simple applications these features may not be important, +in which case it may then be the right decision not to use Quartz.NET.

# Miscellaneous Questions

# How many jobs is Quartz capable of running?

This is a tough question to answer... the answer is basically "it depends".

I know you hate that answer, to here's some information about what it depends "on".

First off, the JobStore that you use plays a significant factor. +The RAM-based JobStore is MUCH (1000x) faster than the ADO.NET-based JobStore. +The speed of AdoJobStore depends almost entirely on the speed of the +connection to your database, which data base system that you use, and what +hardware the database is running on. Quartz actually does very little +processing itself, nearly all of the time is spent in the database. Of course +RAMJobStore has a more finite limit on how many Jobs & Triggers can be stored, +as you're sure to have less RAM than hard-drive space for a database. +You may also look at the FAQ "How do I improve the performance of AdoJobStore?"

So, the limitting factor of the number of Triggers and Jobs Quartz can "store" +and monitor is really the amount of storage space available to the JobStore +(either the amount of RAM or the amount of disk space).

Now, aside from "how many can I store?" is the question of "how many jobs +can Quartz be running at the same moment in time?"

One thing that CAN slow down quartz itself is using a lot of listeners +(TriggerListeners, JobListeners, and SchedulerListeners). The time spent in +each listener obviously adds into the time spent "processing" a job's +execution, outside of actual execution of the job. This doesn't mean that +you should be terrified of using listeners, it just means that you should +use them judiciously - don't create a bunch of "global" listeners if you can +really make more specialized ones. Also don't do "expensive" things in the +listeners, unless you really need to. Also be mindful that many +plug-ins (such as the "history" plugin) are actually listeners.

The actual number of jobs that can be running at any moment in time is +limitted by the size of the thread pool. If there are five threads in +the pool, no more than five jobs can run at a time. Be careful of making a +lot of threads though, as the VM, Operating System, and CPU all have a hard +time juggling lots of threads, and performance degrades just because of all +of the management. In most cases performance starts to tank as you get into +the hundreds of threads. Be mindful that if you're running within an +application server, it probably has created at least a few dozen threads +of its own!

Aside from those factors, it really comes down to what your jobs DO. +If your jobs take a long time to complete their work, and/or their work is +very CPU-intensive, then you're obviously not going to be able to run very +many jobs at once, nor very many in a given spanse of time.

Finally, if you just can't get enough horse-power out of one Quartz instance, +you can always load-balance many Quartz instances (on separate machines). +Each will run the jobs out of the shared database on a first-come first-serve +basis, as quickly as the triggers need fired.

So here you are this far into the answer of "how many", and I still +haven't given you a number And I really hate to, because of all of the +variables mentioned above. So let me just say, there are installments of +Quartz Java out there that are managing hundreds-of-thousands of Jobs and Triggers, +and that at any given moment in time are executing dozens of jobs - and this +excludes using load-balancing. With this in mind, most people should feel +confident that they can get the performance out of Quartz that they need.

# Questions About Jobs

# How can I control the instantiation of Jobs?

See Quartz.Spi.IJobFactory and the Quartz.IScheduler.JobFactory property.

# How do I keep a Job from being removed after it completes?

Set the property JobDetail.Durable = true - which instructs Quartz not to +delete the Job when it becomes an "orphan" (when the Job not longer has a +Trigger referencing it).

# How do I keep a Job from firing concurrently?

Quartz.NET 2.x

Implement IJob and also decorate your job class with [DisallowConcurrentExecution] attribute. Read the API +documentation for DisallowConcurrentExecutionAttribute for more information.

Quartz.NET 1.x

Make the job class implement IStatefulJob rather than IJob. Read the API +documentation for IStatefulJob for more information.

# How do I stop a Job that is currently executing?

Quartz 1.x and 2x: See the Quartz.IInterruptableJob interface, and the IScheduler.Interrupt(string, string) method.

Quartz 3.x: See IJobExecutionContext's CancellationToken.IsCancellationRequested

# Questions About Triggers

# How do I chain Job execution? Or, how do I create a workflow?

There currently is no "direct" or "free" way to chain triggers with Quartz. +However there are several ways you can accomplish it without much effort. +Below is an outline of a couple approaches:

One way is to use a listener (i.e. a TriggerListener, JobListener or +SchedulerListener) that can notice the completion of a job/trigger and then +immediately schedule a new trigger to fire. This approach can get a bit +involved, since you'll have to inform the listener which job follows which

  • and you may need to worry about persistence of this information.

Another way is to build a Job that contains within its JobDataMap the name +of the next job to fire, and as the job completes (the last step in its +Execute() method) have the job schedule the next job. Several people are +doing this and have had good luck. Most have made a base (abstract) class +that is a Job that knows how to get the job name and group out of the +JobDataMap using special keys (constants) and contains code to schedule the +identified job. Then they simply make extensions of this class that included +the additional work the job should do.

In the future, Quartz will provide a much cleaner way to do this, but until +then, you'll have to use one of the above approaches, or think of yet another +that works better for you.

# Why isn't my trigger firing?

The most common reason for this is not having called Scheduler.Start(), +which tells the scheduler to start firing triggers.

The second most common reason is that the trigger or trigger group +has been paused.

# Daylight Saving Time and Triggers

CronTrigger and SimpleTrigger each handle daylight savings time in their own +way - each in the way that is intuitive to the trigger type.

First, as a review of what daylight savings time is, please read this resource: +http://webexhibits.org/daylightsaving/g.html . Some readers may be unaware +that the rules are different for different nations/contents. For example, +the 2005 daylight savings time starts in the United States on April 3, but +in Egypt on April 29. It is also important to know that not only the dates +are different for different locals, but the time of the shift is different +as well. Many places shift at 2:00 am, but others shift time at 1:00 am, +others at 3:00 am, and still others right at midnight.

SimpleTrigger allows you to schedule jobs to fire every N milliseconds. +As such, it has to do nothing in particular with respect to daylight +savings time in order to "stay on schedule" - it simply keeps firing every +N milliseconds. Regardless your SimpleTrigger is firing every 10 seconds, +or every 15 minutes, or every hour or every 24 hours it will continue to do +so. However the implication of this which confuses some users is that if +your SimpleTrigger is firing say every 12 hours, before daylight savings +switches it may be firing at what appears to be 3:00 am and 3:00 pm, +but after daylight savings 4:00 am and 4:00 pm. This is not a bug

  • the trigger has kept firing exacly every N milliseconds, it just that the +"name" of that time that humans impose on that moment has changed.

CronTrigger allows you to schedule jobs to fire at certain moments with +respect to a "gregorian calendar". Hence, if you create a trigger to fire +every day at 10:00 am, before and after daylight savings time switches it +will continue to do so. However, depending on whether it was the Spring or +Autumn daylight savings event, for that particular Sunday, the actual time +interval between the firing of the trigger on Sundary morning at 10:00 am +since its firing on Saturday morning at 10:00 am will not be 24 hours, +but will instead be 23 or 25 hours respectively.

There is one additional point users must understand about CronTrigger with +respect to daylight savings. This is that you should take careful thought +about creating schedules that fire between midnight and 3:00 am (the critical +window of time depends on your trigger's locale, as explained above). +The reason is that depending on your trigger's schedule, and the particular +daylight event, the trigger may be skipped or may appear to not fire for an +hour or two. As examples, say you are in the United States, where daylight +savings events occur at 2:00 am. If you have a CronTrrigger that fires every +day at 2:15 am, then on the day of the beginning of daylight savings time +the trigger will be skipped, since, 2:15 am never occurs that day. If you +have a CronTrigger that fires every 15 minutes of every hour of every day, +then on the day daylight savings time ends you will have an hour of time +for which no triggerings occur, because when 2:00 am arrives, it will become +1:00 am again, however all of the firings during the one o'clock hour have +already occurred, and the trigger's next fire time was set to 2:00 am

  • hence for the next hour no triggerings will occur.

In summary, all of this makes perfect sense, and should be easy to remember +if you keep these two rules in mind:

  • SimpleTrigger ALWAYS fires exacly every N seconds, with no relation to the time of day.
  • CronTrigger ALWAYS fires at a given time of day and then computes its next time to fire. If that time does not occur on a given day, the trigger will be skipped. If the time occurs twice in a given day, it only fires once, because after firing on that time the first time, it computes the next time of day to fire on.

# Questions About AdoJobStore

# How do I improve the performance of AdoJobStore?

There are a few known ways to speed up AdoJobStore, only one of which is +very practical.

First, the obvious, but not-so-practical:

  • Buy a better (faster) network between the machine that runs Quartz, and the machine that runs your RDBMS.
  • Buy a better (more powerful) machine to run your database on.
  • Buy a better RDBMS.

Secondly, use driver delegate implementation that is specific to your database, like SQLServerDelegate, for best performance.

TIP

You should also always prefer the latest version of the library. Quartz.NET 2.0 is much more efficient than 1.x series and 2.2.x line again has AdoJobStore related performance improvements over earlier 2.x releases.

# Quartz in web environment

# Scheduler keeps stopping when application pool gets recycled

By default IIS recycles and stops app pools from time to time. This means that even if you have Application_Start event to start Quartz when web app is being first accessed, the scheduler might get disposed later on due to site inactivity.

If you have a IIS 8 available, you can configure your site to be preloaded and kept running. See this blog post (opens new window) for details.

+ + + diff --git a/documentation/index.html b/documentation/index.html new file mode 100644 index 000000000..ecc82a4cb --- /dev/null +++ b/documentation/index.html @@ -0,0 +1,55 @@ + + + + + + Documentation | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/quartz-1.x/index.html b/documentation/quartz-1.x/index.html new file mode 100644 index 000000000..489deca59 --- /dev/null +++ b/documentation/quartz-1.x/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/quartz-1.x/tutorial/advanced-enterprise-features.html b/documentation/quartz-1.x/tutorial/advanced-enterprise-features.html new file mode 100644 index 000000000..af0cdd4b7 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/advanced-enterprise-features.html @@ -0,0 +1,70 @@ + + + + + + Lesson 11: Advanced (Enterprise) Features | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Clustering

Clustering currently only works with the AdoJobstore (JobStoreTX). Features include load-balancing and job fail-over (if the JobDetail's "request recovery" flag is set to true).

Enable clustering by setting the "quartz.jobStore.clustered" property to "true". +Each instance in the cluster should use the same copy of the quartz properties. +Exceptions of this would be to use properties that are identical, with the following allowable exceptions: +Different thread pool size, and different value for the "quartz.scheduler.instanceId" property. +Each node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing "AUTO" as the value of this property.

Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly +(the clocks must be within a second of each other). See http://www.boulder.nist.gov/timefreq/service/its.htm +if you are unfamiliar with how to do this.

Never fire-up a non-clustered instance against the same set of tables that any other instance is running against. +You may get serious data corruption, and will definitely experience eratic behavior.

+ + + diff --git a/documentation/quartz-1.x/tutorial/configuration-resource-usage-and-scheduler-factory.html b/documentation/quartz-1.x/tutorial/configuration-resource-usage-and-scheduler-factory.html new file mode 100644 index 000000000..e3a952c4d --- /dev/null +++ b/documentation/quartz-1.x/tutorial/configuration-resource-usage-and-scheduler-factory.html @@ -0,0 +1,94 @@ + + + + + + Lesson 10: Configuration, Resource Usage and SchedulerFactory | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz is architected in modular way, and therefore to get it running, several components need to be "snapped" together. +Fortunately, some helpers exist for making this happen.

The major components that need to be configured before Quartz can do its work are:

  • ThreadPool
  • JobStore
  • DataSources (if necessary)
  • The Scheduler itself

The ThreadPool provides a set of Threads for Quartz to use when executing Jobs. +The more threads in the pool, the greater number of Jobs that can run concurrently. +However, too many threads may bog-down your system. +Most Quartz users find that 5 or so threads are plenty- because they have fewer than 100 jobs at any given time, +the jobs are not generally scheduled to run at the same time, and the jobs are short-lived (complete quickly). +Other users find that they need 10, 15, 50 or even 100 threads - because they have tens-of-thousands +of triggers with various schedules - which end up having an average of between 10 and 100 jobs trying to +execute at any given moment. Finding the right size for your scheduler's pool is completely dependent on +what you're using the scheduler for. There are no real rules, other than to keep the number of threads as +small as possible (for the sake of your machine's resources) - but make sure you have enough for your Jobs to fire on time. +Note that if a trigger's time to fire arrives, and there isn't an available thread, +Quartz will block (pause) until a thread comes available, then the Job will execute - +some number of milliseconds later than it should have. This may even cause the tread to misfire - if +there is no available thread for the duration of the scheduler's configured "misfire threshold".

A IThreadPool interface is defined in the Quartz.Spi namespace, and you can create a IThreadPool implementation in any way you like. +Quartz ships with a simple (but very satisfactory) thread pool named Quartz.Simpl.SimpleThreadPool. +This IThreadPool implementation simply maintains a fixed set of threads in its pool - never grows, never shrinks. +But it is otherwise quite robust and is very well tested - as nearly everyone using Quartz uses this pool.

JobStores and DataSrouces were discussed in Lesson 9 of this tutorial. Worth noting here, is the fact that all JobStores +implement the IJobStore interface - and that if one of the bundled JobStores does not fit your needs, then you can make your own.

Finally, you need to create your Scheduler instance. The Scheduler itself needs to be given a name and handed +instances of a JobStore and ThreadPool.

# StdSchedulerFactory

StdSchedulerFactory is an implementation of the ISchedulerFactory interface. +It uses a set of properties (NameValueCollection) to create and initialize a Quartz Scheduler. +The properties are generally stored in and loaded from a file, but can also be created by your program and handed directly to the factory. +Simply calling getScheduler() on the factory will produce the scheduler, initialize it (and its ThreadPool, JobStore and DataSources), +and return a handle to its public interface.

There are some sample configurations (including descriptions of the properties) in the "docs/config" directory of the Quartz distribution. +You can find complete documentation in the "Configuration" manual under the "Reference" section of the Quartz documentation.

# DirectSchedulerFactory

DirectSchedulerFactory is another SchedulerFactory implementation. It is useful to those wishing to create their Scheduler +instance in a more programatic way. Its use is generally discouraged for the following reasons: (1) it +requires the user to have a greater understanding of what they're doing, and (2) it does not allow for declaritive +configuration - or in other words, you end up hard-coding all of the scheduler's settings.

# Logging

Quartz.NET uses the Common.Logging framework for all of its logging needs. +Quartz does not produce much logging information - generally just some information during initialization, and +then only messages about serious problems while Jobs are executing. In order to "tune" the logging settings +(such as the amount of output, and where the output goes), you need to understand the Commmon.Logging framework, +which is beyond the scope of this document, please refer to Common.Logging Documentation.

+ + + diff --git a/documentation/quartz-1.x/tutorial/crontriggers.html b/documentation/quartz-1.x/tutorial/crontriggers.html new file mode 100644 index 000000000..de6655f57 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/crontriggers.html @@ -0,0 +1,92 @@ + + + + + + Lesson 6: CronTrigger | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

CronTriggers are often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions, +rather than on the exactly specified intervals of SimpleTrigger.

With CronTrigger, you can specify firing-schedules such as "every Friday at noon", or "every weekday and 9:30 am", +or even "every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday".

Even so, like SimpleTrigger, CronTrigger has a startTime which specifies when the schedule is in force, and an (optional) +endTime that specifies when the schedule should be discontinued.

# Cron Expressions

Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up +of seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:

    1. Seconds
    1. Minutes
    1. Hours
    1. Day-of-Month
    1. Month
    1. Day-of-Week
    1. Year (optional field)

An example of a complete cron-expression is the string "0 0 12 ? * WED" - which means "every Wednesday at 12:00 pm".

Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED") +example could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".

Wild-cards (the '' character) can be used to say "every" possible value of this field. Therefore the '' character in the +"Month" field of the previous example simply means "every month". A '*' in the Day-Of-Week field would obviously mean "every day of the week".

All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers +0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful +about how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings +JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday) +or by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.

The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes, +starting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour, +starting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.

The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify "no specific value". +This is useful when you need to specify something in one of the two fields, but not the other. +See the examples below (and CronTrigger API documentation) for clarification.

The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last", +but it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means +"the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, +it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - +for example "6L" or "FRIL" both mean "the last friday of the month". When using the 'L' option, it is important not to specify lists, +or ranges of values, as you'll get confusing results.

The 'W' is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month".

The '#' is used to specify "the nth" XXX weekday of the month. For example, the value of "6#3" or "FRI#3" in the day-of-week field means "the third Friday of the month".

# Example Cron Expressions

Here are a few more examples of expressions and their meanings - you can find even more in the API documentation for CronTrigger

CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes

"0 0/5 * * * ?"
+

CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).

"10 0/5 * * * ?"
+

CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.

"0 30 10-13 ? * WED,FRI"
+

CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month. +Note that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30

"0 0/30 8-9 5,20 * ?"
+

Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am, +and every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.

# CronTrigger Misfire Instructions

The following instructions can be used to inform Quartz what it should do when a misfire occurs for CronTrigger. +(Misfire situations were introduced in the More About Triggers section of this tutorial). These instructions are defined in MisfireInstruction.CronTrigger as +constants (and API documentation has description for their behavior). The instructions include:

  • DoNothing
  • FireOnceNow

All triggers have the MisfireInstrution.SmartPolicy instruction available for use, and this instruction is also the default for all trigger types. +The 'smart policy' instruction is interpreted by CronTrigger as MisfireInstruction.CronTrigger.FireOnceNow. The API documentation for the +CronTrigger.UpdateAfterMisfire() method explains the exact details of this behavior.

+ + + diff --git a/documentation/quartz-1.x/tutorial/index.html b/documentation/quartz-1.x/tutorial/index.html new file mode 100644 index 000000000..03b3b3d12 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET 1.x Tutorial | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/documentation/quartz-1.x/tutorial/job-stores.html b/documentation/quartz-1.x/tutorial/job-stores.html new file mode 100644 index 000000000..10ee4b54a --- /dev/null +++ b/documentation/quartz-1.x/tutorial/job-stores.html @@ -0,0 +1,106 @@ + + + + + + Lesson 9: JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

JobStore's are responsible for keeping track of all the "work data" that you give to the scheduler: +jobs, triggers, calendars, etc. Selecting the appropriate IJobStore implementation for your Quartz scheduler instance is an important step. +Luckily, the choice should be a very easy one once you understand the differences between them. +You declare which JobStore your scheduler should use (and it's configuration settings) in the properties file (or object) that +you provide to the SchedulerFactory that you use to produce your scheduler instance.

Never use a JobStore instance directly in your code. For some reason many people attempt to do this. +The JobStore is for behind-the-scenes use of Quartz itself. You have to tell Quartz (through configuration) which JobStore to use, but then you should only work with the Scheduler interface in your code.

# RAMJobStore

RAMJobStore is the simplest JobStore to use, it is also the most performant (in terms of CPU time). +RAMJobStore gets its name in the obvious way: it keeps all of its data in RAM. This is why it's lightning-fast, +and also why it's so simple to configure. The drawback is that when your application ends (or crashes) all of +the scheduling information is lost - this means RAMJobStore cannot honor the setting of "non-volatility" on jobs and triggers. +For some applications this is acceptable - or even the desired behavior, but for other applications, this may be disasterous.

To use RAMJobStore (and assuming you're using StdSchedulerFactory) you don't need to do anything special. Default configuration +of Quartz.NET uses RAMJobStore as job store implementation.

# ADO.NET Job Store (AdoJobStore)

AdoJobStore is also aptly named - it keeps all of its data in a database via ADO.NET. +Because of this it is a bit more complicated to configure than RAMJobStore, and it also is not as fast. +However, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.

To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use. +You can find table-creation SQL scripts in the "database/dbtables" directory of the Quartz.NET distribution. +If there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB. +One thing to note is that in these scripts, all the the tables start with the prefix "QRTZ_" +such as the tables "QRTZ_TRIGGERS", and "QRTZ_JOB_DETAIL"). This prefix can actually be anything you'd like, as long as you inform AdoJobStore +what the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables, +for multiple scheduler instances, within the same database.

Currently the only option for the internal implementation of job store is JobStoreTX which creates transactions by itself. +This is different from Java version of Quartz where there is also option to choose JobStoreCMT which uses J2EE container +managed transactions.

The last piece of the puzzle is setting up a data source from which AdoJobStore can get connections to your database. +Data sources are defined in your Quartz.NET properties. Data source information contains the connection string +and ADO.NET delegate information.

Configuring Quartz to use JobStoreTx

quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz
+

Next, you need to select a IDriverDelegate implementation for the JobStore to use. +The DriverDelegate is responsible for doing any ADO.NET work that may be needed for your specific database. +StdAdoDelegate is a delegate that uses "vanilla" ADO.NET code (and SQL statements) to do its work. +If there isn't another delegate made specifically for your database, try using this delegate - +special delegates usually have better performance or workarounds for database specific issues. +Other delegates can be found in the "Quartz.Impl.AdoJobStore" namespace, or in its sub-namespaces.

NOTE: Quartz.NET will issue warning if you are using the default StdAdoDelegate as it has poor performance +when you have a lot of triggers to select from. Specific delegates have special SQL to limit result +set length (SQLServerDelegate uses TOP n, PostgreSQLDelegate LIMIT n, OracleDelegate ROWCOUNT() <= n etc.).

Once you've selected your delegate, set its class name as the delegate for AdoJobStore to use.

Configuring AdoJobStore to use a DriverDelegate

quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz
+

Next, you need to inform the JobStore what table prefix (discussed above) you are using.

Configuring AdoJobStore with the Table Prefix

quartz.jobStore.tablePrefix = QRTZ_
+

And finally, you need to set which data source should be used by the JobStore. The named data source must also be defined in your Quartz properties. +In this case, we're specifying that Quartz should use the data source name "myDS" (that is defined elsewhere in the configuration properties).

Configuring AdoJobStore with the name of the data source to use

quartz.jobStore.dataSource = myDS
+

One last thing that is needed for the configuration is to set data source connection string information and database provider. Connection +string is the standard ADO.NET connection which is driver specific. Database provider is an abstraction of database drivers to create +loose coupling betweeb database drivers and Quartz.

Setting Data Source's Connection String And Database Provider

 quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartz;Uid=quartznet;Pwd=quartznet
+ quartz.dataSource.myDS.provider = MySql-50
+

Currently following database providers are supported:

  • SqlServer-11 - SQL Server driver for .NET Framework 1.1
  • SqlServer-20 - SQL Server driver for .NET Framework 2.0
  • OracleClient-20 - Microsoft's Oracle Driver (comes bundled with .NET Framework)
  • OracleODP-20 - Oracle's Oracle Driver
  • MySql-10 - MySQL Connector/.NET v. 1.0.7
  • MySql-109 - MySQL Connector/.NET v. 1.0.9
  • MySql-50 - MySQL Connector/.NET v. 5.0 (.NET 2.0)
  • MySql-51 - MySQL Connector/:NET v. 5.1 (.NET 2.0)
  • SQLite-10 - SQLite ADO.NET 2.0 Provider v. 1.0.56 (.NET 2.0)
  • Firebird-201 - Firebird ADO.NET 2.0 Provider v. 2.0.1 (.NET 2.0)
  • Firebird-210 - Firebird ADO.NET 2.0 Provider v. 2.1.0 (.NET 2.0)

If your Scheduler is very busy (i.e. nearly always executing the same number of jobs as the size of the thread pool, then you should +probably set the number of connections in the data source to be the about the size of the thread pool + 1.This is commonly configured +int the ADO.NET connection string - see your driver implementation for details.

The "quartz.jobStore.useProperties" config parameter can be set to "true" (defaults to false) in order to instruct AdoJobStore that all values in JobDataMaps will be strings, +and therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column. This is much safer in the long term, +as you avoid the class versioning issues that there are with serializing your non-String classes into a BLOB.

Configuring AdoJobStore to use strings as JobDataMap values (recommended)

quartz.jobStore.useProperties = true
+
+ + + diff --git a/documentation/quartz-1.x/tutorial/jobs-and-triggers.html b/documentation/quartz-1.x/tutorial/jobs-and-triggers.html new file mode 100644 index 000000000..fd9f0d3e8 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/jobs-and-triggers.html @@ -0,0 +1,96 @@ + + + + + + Lesson 2: Jobs And Triggers | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

As mentioned previously, you can make .NET component executable by the scheduler simply by making it +implement the IJob interface. Here is the interface:

IJob Interface

    namespace Quartz
+    {
+        public interface IJob
+        {
+            void Execute(JobExecutionContext context);
+        }
+    }
+

In case you couldn't guess, when the job's trigger fires (more on that in a moment), the Execute(..) method +is invoked by the scheduler. The JobExecutionContext object that is passed to this method provides +the job instance with information about its "run-time" environment - a handle to the IScheduler that executed it, +a handle to the Trigger that triggered the execution, the job's JobDetail object, and a few other items.

The JobDetail object is created by the Quartz.NET client (your program) at the time the Job is added +to the scheduler. It contains various property settings for the Job, as well as a JobDataMap, which can be used +to store state information for a given instance of your job class.

Trigger objects are used to trigger the execution (or 'firing') of jobs. When you wish to schedule a job, +you instantiate a trigger and 'tune' its properties to provide the scheduling you wish to have. +Triggers may also have a JobDataMap associated with them - this is useful to passing parameters to a Job +that are specific to the firings of the trigger. Quartz.NET ships with a handful of different trigger types, +but the most commonly used types are SimpleTrigger and CronTrigger.

SimpleTrigger is handy if you need 'one-shot' execution (just single execution of a job at a given moment in time), +or if you need to fire a job at a given time, and have it repeat N times, with a delay of T between executions. +CronTrigger is useful if you wish to have triggering based on calendar-like schedules - such as "every Friday, +at noon" or "at 10:15 on the 10th day of every month."

# Why Jobs AND Triggers?

Many job schedulers do not have separate notions of jobs and triggers. Some define a 'job' as simply an +execution time (or schedule) along with some small job identifier. Others are much like the union +of Quartz.NET's job and trigger objects. While developing Quartz for Java, Quartz team decided that it made sense to create +a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) +many benefits.

For example, jobs can be created and stored in the job scheduler independent of a trigger, and many triggers +can be associated with the same job. Another benefit of this loose-coupling is the ability to configure jobs +that remain in the scheduler after their associated triggers have expired, so that that it can be rescheduled +later, without having to re-define it. It also allows you to modify or replace a trigger without having to +re-define its associated job.

# Identifiers

Jobs and Triggers are given identifying names as they are registered with the Quartz.NET scheduler. +Jobs and triggers can also be placed into 'groups' which can be useful for organizing your jobs and triggers +into categories for later maintenance. The name of a job or trigger must be unique within its group - or in other +words, the true identifier of a job or trigger is its name + group. If you leave the group of the +Job or Trigger 'null', it is equivalent to having specified SchedulerConstants.DefaultGroup.

You now have a general idea about what Jobs and Triggers are, you can learn more about them in +Lesson 3: More About Jobs & JobDetails and Lesson 4: More About Triggers

+ + + diff --git a/documentation/quartz-1.x/tutorial/miscellaneous-features.html b/documentation/quartz-1.x/tutorial/miscellaneous-features.html new file mode 100644 index 000000000..6c0e7af48 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/miscellaneous-features.html @@ -0,0 +1,69 @@ + + + + + + Lesson 12: Miscellaneous Features of Quartz | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Plug-Ins

Quartz provides an interface (ISchedulerPlugin) for plugging-in additional functionality.

Plugins that ship with Quartz to provide various utililty capabilities can be found documented in the Quartz.Plugins namespace. +They provide functionality such as auto-scheduling of jobs upon scheduler startup, logging a history of job and trigger events, +and ensuring that the scheduler shuts down cleanly when the virtual machine exits.

# JobFactory

When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler. +The default JobFactory simply activates a new instance of the job class. You may want to create your own implementation +of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.

See the IJobFactory interface, and the associated Scheduler.SetJobFactory(fact) method.

# 'Factory-Shipped' Jobs

Quartz also provides a number of utility Jobs that you can use in your application for doing things like sending +e-mails and invoking remote objects. These out-of-the-box Jobs can be found documented in the Quartz.Jobs namespace.

+ + + diff --git a/documentation/quartz-1.x/tutorial/more-about-jobs.html b/documentation/quartz-1.x/tutorial/more-about-jobs.html new file mode 100644 index 000000000..585120123 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/more-about-jobs.html @@ -0,0 +1,162 @@ + + + + + + Lesson 3: More About Jobs & JobDetails | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

As you've seen, jobs are rather easy to implement. There are just a few more things that you need to understand about +the nature of jobs, about the Execute(..) method of the IJob interface, and about JobDetails.

While a class that you implement is the actual "job", Quartz needs to be informed about various attributes +that you may wish the job to have. This is done via the JobDetail class, which was mentioned briefly in the previous section. +Software 'archaeologists' may be interested to know that in an older incarnation of Quartz for Java, the implementation of the +functionality of JobDetail was imposed upon the implementor of each Job class by having all of JobDetail's 'getter' methods on +the Job interface itself. This forced a cumbersome job of re-implementing virtually identical code on every Job class - +which was really dumb... thus JobDetail class was created.

Let's take a moment now to discuss a bit about the 'nature' of jobs and the life-cycle of job instances within Quartz.NET. +First lets take a look back at some of that snippet of code we saw in Lesson 1:

Using Quartz.NET

    // construct a scheduler factory
+    ISchedulerFactory schedFact = new StdSchedulerFactory();
+    
+    // get a scheduler
+    IScheduler sched = schedFact.GetScheduler();
+    sched.Start();
+    
+    // construct job info
+    JobDetail jobDetail = new JobDetail("myJob", null, typeof(DumbJob));
+    // fire every hour
+    Trigger trigger = TriggerUtils.MakeHourlyTrigger();
+    // start on the next even hour
+    trigger.StartTime = TriggerUtils.GetEvenHourDate(DateTime.UtcNow);  
+    trigger.Name = "myTrigger";
+    sched.ScheduleJob(jobDetail, trigger); 
+

Now consider the job class DumbJob defined as such:

    public class DumbJob : IJob
+    {
+        public DumbJob() {
+        }
+    
+        public void Execute(JobExecutionContext context)
+        {
+            Console.WriteLine("DumbJob is executing.");
+        }
+    }
+

Notice that we 'feed' the scheduler a JobDetail instance, and that it refers to the job to be executed by simply +providing the job's class. Each (and every) time the scheduler executes the job, it creates a new instance of the +class before calling its Execute(..) method. One of the ramifications of this behavior is the fact that jobs must +have a no-arguement constructor. Another ramification is that it does not make sense to have data-members defined +on the job class - as their values would be 'cleared' every time the job executes.

You may now be wanting to ask "how can I provide properties/configuration for a Job instance?" and "how can I +keep track of a job's state between executions?" The answer to these questions are the same: the key is the JobDataMap, +which is part of the JobDetail object.

# JobDataMap

The JobDataMap can be used to hold any number of (serializable) objects which you wish to have made available +to the job instance when it executes. JobDataMap is an implementation of the IDictionary interface, and has some added convenience methods for storing and retreiving data of primitive types.

Here's some quick snippets of putting data into the JobDataMap prior to adding the job to the scheduler:

Setting Values in a JobDataMap

    jobDetail.JobDataMap["jobSays"] = "Hello World!";
+    jobDetail.JobDataMap["myFloatValue"] =  3.141f;
+    jobDetail.JobDataMap["myStateData"] = new ArrayList(); 
+

Here's a quick example of getting data from the JobDataMap during the job's execution:

Getting Values from a JobDataMap

    public class DumbJob : IJob
+    {
+        public void Execute(JobExecutionContext context)
+        {
+            string instName = context.JobDetail.Name;
+            string instGroup = context.JobDetail.Group;
+    
+            JobDataMap dataMap = context.JobDetail.JobDataMap;
+    
+            string jobSays = dataMap.GetString("jobSays");
+            float myFloatValue = dataMap.GetFloat("myFloatValue");
+            ArrayList state = (ArrayList) dataMap["myStateData"];
+            state.Add(DateTime.UtcNow);
+    
+            Console.WriteLine("Instance {0} of DumbJob says: {1}", instName, jobSays);
+        }
+    } 
+

If you use a persistent JobStore (discussed in the JobStore section of this tutorial) you should use some care +in deciding what you place in the JobDataMap, because the object in it will be serialized, and they therefore +become prone to class-versioning problems. Obviously standard .NET types should be very safe, but beyond that, +anytime someone changes the definition of a class for which you have serialized instances, care has to be taken +not to break compatibility. Optionally, you can put AdoJobStore and JobDataMap into a mode where only primitives +and strings can be stored in the map, thus eliminating any possibility of later serialization problems.

# Stateful vs. Non-Stateful Jobs

Triggers can also have JobDataMaps associated with them. This can be useful in the case where you have a Job that +is stored in the scheduler for regular/repeated use by multiple Triggers, yet with each independent triggering, +you want to supply the Job with different data inputs.

The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge +of the JobDataMap found on the JobDetail and the one found on the Trigger, with the value in the latter overriding +any same-named values in the former.

Here's a quick example of getting data from the JobExecutionContext's merged JobDataMap during the job's execution:

Getting Values from the JobExecutionContext convenience/merged JobDataMap

    public class DumbJob : IJob
+    {
+        public void Execute(JobExecutionContext context)
+        {
+            string instName = context.JobDetail.Name;
+            string instGroup = context.JobDetail.Group;
+    
+            // Note the difference from the previous example
+            JobDataMap dataMap = context.MergedJobDataMap;
+    
+            string jobSays = dataMap.GetString("jobSays");
+            float myFloatValue = dataMap.GetFloat("myFloatValue");
+            ArrayList state = (ArrayList) dataMap.Get("myStateData");
+            state.Add(DateTime.UtcNow);
+    
+            Console.WriteLine("Instance {0} of DumbJob says: {1}", instName, jobSays);
+        }
+    } 
+

# StatefulJob

Now, some additional notes about a job's state data (aka JobDataMap): A Job instance can be defined as "stateful" or "non-stateful". +Non-stateful jobs only have their JobDataMap stored at the time they are added to the scheduler. This means that any changes made +to the contents of the job data map during execution of the job will be lost, and will not seen by the job the next time it executes. +You have probably guessed, a stateful job is just the opposite - its JobDataMap is re-stored after every execution of the job. +One side-effect of making a job stateful is that it cannot be executed concurrently. Or in other words: if a job is stateful, and +a trigger attempts to 'fire' the job while it is already executing, the trigger will block (wait) until the previous execution completes.

You 'mark' a Job as stateful by having it implement the IStatefulJob interface, rather than the IJob interface.

# Job 'Instances'

One final point on this topic that may or may not be obvious by now: You can create a single job class, and store many +'instance definitions' of it within the scheduler by creating multiple instances of JobDetails - each with its own set of properties +and JobDataMap - and adding them all to the scheduler.

When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler. The default +JobFactory simply calls Activator.CreateInstance behind the scenes on the job class. +You may want to create your own implementation of JobFactory to accomplish things such as having your application's IoC or +DI container produce/initialize the job instance.

# Other Attributes Of Jobs

Here's a quick summary of the other properties which can be defined for a job instance via the JobDetail object:

  • Durable - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it.
  • Volatile - if a job is volatile, it is not persisted between re-starts of the Quartz scheduler.
  • RequestsRecovery - if a job "requests recovery", and it is executing during the time of a 'hard shutdown' of the scheduler (i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. In this case, the JobExecutionContext.IsRecovering property will return true.
  • JobListeners - a job can have a set of zero or more JobListeners associated with it. When the job executes, the listeners are notified. More discussion on JobListeners can be found in the section of this document that is dedicated to the topic of TriggerListeners & JobListeners.

# The Job.Execute(..) Method

Finally, we need to inform you of a few details of the IJob.Execute(..) method. The only type of exception +that you are allowed to throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire +contents of the execute method with a 'try-catch' block. You should also spend some time looking at the documentation for the +JobExecutionException, as your job can use it to provide the scheduler various directives as to how you want the exception to be handled.

+ + + diff --git a/documentation/quartz-1.x/tutorial/more-about-triggers.html b/documentation/quartz-1.x/tutorial/more-about-triggers.html new file mode 100644 index 000000000..b2a9a45c3 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/more-about-triggers.html @@ -0,0 +1,151 @@ + + + + + + Lesson 4: More About Triggers | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Like jobs, triggers are relatively easy to work with, but do contain a variety of customizable options that you need to +be aware of and understand before you can make full use of Quartz.NET. Also, as noted earlier, there are different types of triggers, +that you can select to meet different scheduling needs.

# Calendars

Quartz Calendar objects can be associated with triggers at the time the trigger is stored in the scheduler. +Calendars are useful for excluding blocks of time from the the trigger's firing schedule. For instance, you could +create a trigger that fires a job every weekday at 9:30 am, but then add a Calendar that excludes all of the business's holidays.

Calendar's can be any serializable objects that implement the ICalendar interface, which looks like this:

namespace Quartz
+{
+    public interface ICalendar
+    {
+        string Description { get; set; }
+
+        ICalendar CalendarBase { set; get; }
+
+        bool IsTimeIncluded(DateTime timeUtc);
+
+        DateTime GetNextIncludedTimeUtc(DateTime timeUtc);
+    }
+} 
+

Notice that the parameters to these methods are of the long type. As you may guess, they are timestamps in millisecond format. +This means that calendars can 'block out' sections of time as narrow as a millisecond. Most likely, you'll be interested in +'blocking-out' entire days. As a convenience, Quartz includes the class HolidayCalendar, which does just that.

Calendars must be instantiated and registered with the scheduler via the AddCalendar(..) method. If you use HolidayCalendar, +after instantiating it, you should use its AddExcludedDate(DateTime date) method in order to populate it with the days you wish +to have excluded from scheduling. The same calendar instance can be used with multiple triggers such as this:

Using Calendars

    HolidayCalendar cal = new HolidayCalendar();
+    cal.AddExcludedDate(someDate);
+    
+    sched.AddCalendar("myHolidays", cal, false);
+    
+    // fire every one hour interval
+    Trigger trigger = TriggerUtils.MakeHourlyTrigger();
+    // start on the next even hour
+    trigger.StartTimeUtc = TriggerUtils.GetEvenHourDate(DateTime.Now); 
+    trigger.Name = "myTrigger1";
+    
+    trigger.CalendarName = "myHolidays";
+    
+    // .. schedule job with trigger
+    
+    // fire every day at 08:00
+    Trigger trigger2 = TriggerUtils.MakeDailyTrigger(8, 0);
+    // begin immediately
+    trigger.StartTimeUtc = DateTime.UtcNow; 
+    trigger2.Name = "myTrigger2";
+    trigger2.CalendarName = "myHolidays";
+    
+    // .. schedule job with trigger2 
+

The details of the values passed in the SimpleTrigger constructors will be explained in the next section. +For now, just believe that the code above creates two triggers: one that will repeat every 60 seconds forever, and one that +will repeat five times with a five day interval between firings. However, any of the firings that would have +occurred during the period excluded by the calendar will be skipped.

# Priority

Sometimes, when you have many Triggers (or few worker threads in your Quartz.NET thread pool), Quartz.NET may not have enough resources to +immediately fire all of the Triggers that are scheduled to fire at the same time. In this case, you may want to control +which of your Triggers get first crack at the available Quartz.NET worker threads. For this purpose, you can set the priority property on a Trigger. +If N Triggers are to fire at the same time, but there are only Z worker threads currently available, then the first Z Triggers with the highest priority will get first dibs. +If you do not set a priority on a Trigger, then it will use the default priority of 5. +Any integer value is allowed for priority, positive or negative.

Note: When a Trigger is detected to require recovery, its recovery is scheduled with the same priority as the original Trigger.

Priority Example

    // All three Triggers will be scheduled to fire 5 minutes from now.
+    DateTime d = DateTime.UtcNow.AddMinutes(5);
+    
+    Trigger trig1 = new SimpleTrigger("T1", "MyGroup", d);
+    Trigger trig2 = new SimpleTrigger("T2", "MyGroup", d);
+    Trigger trig3 = new SimpleTrigger("T3", "MyGroup", d);
+    
+    JobDetail jobDetail = new JobDetail("MyJob", "MyGroup", typeof(NoOpJob));
+    
+    // Trigger1 does not have its priority set, so it defaults to 5
+    sched.ScheduleJob(jobDetail, trig1);
+    
+    // Trigger2 has its priority set to 10
+    trig2.JobName = jobDetail.Name;
+    trig2.Priority = 10;
+    sched.ScheduleJob(trig2);
+    
+    // Trigger2 has its priority set to 1
+    trig3.JobName = jobDetail.Name;
+    trig3.Priority = 1;
+    sched.ScheduleJob(trig3);
+    
+    // Five minutes from now, when the scheduler invokes these three triggers
+    // they will be allocated worker threads in decreasing order of their
+    // priority: Trigger2(10), Trigger1(5), Trigger3(1) 
+

# Misfire Instructions

Another important property of a Trigger is its "misfire instruction". A misfire occurs if a persistent trigger "misses" +its firing time because of the scheduler being shutdown, or because there are no available threads in Quartz's thread pool for executing the job. +The different trigger types have different misfire instructions available to them. By default they use a 'smart policy' instruction

  • which has dynamic behavior based on trigger type and configuration. When the scheduler starts, it searches for any persistent triggers that +have misfired, and it then updates each of them based on their individually configured misfire instructions.

When you start using Quartz in your +own projects, you should make yourself familiar with the misfire instructions that are defined on the given trigger types, +and explained in their API documentation. More specific information about misfire instructions will be given within +the tutorial lessons specific to each trigger type. The misfire instruction for a given trigger instance can be configured +using the MisfireInstruction property.

# TriggerUtils - Triggers Made Easy

The TriggerUtils class contains conveniences to help you create triggers and dates without +having to monkey around with DateTime objects. Use this class to easily make triggers that fire every minute, +hour, day, week, month, etc. Also use this class to generate dates that are rounded to the nearest second, minute or hour - +this can be very useful for setting trigger start-times.

# Trigger Listeners

Finally, triggers may have registered listeners, just as jobs may. +Objects implementing the ITriggerListener interface will receive notifications as a trigger is fired.

+ + + diff --git a/documentation/quartz-1.x/tutorial/scheduler-listeners.html b/documentation/quartz-1.x/tutorial/scheduler-listeners.html new file mode 100644 index 000000000..0a68511fc --- /dev/null +++ b/documentation/quartz-1.x/tutorial/scheduler-listeners.html @@ -0,0 +1,87 @@ + + + + + + Lesson 8: SchedulerListeners | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

SchedulerListeners are much like ITriggerListeners and IJobListeners, except they receive notification of +events within the scheduler itself - not necessarily events related to a specific trigger or job.

Scheduler-related events include: the addition of a job/trigger, the removal of a job/trigger, a serious error +within the scheduler, notification of the scheduler being shutdown, and others.

The ISchedulerListener Interface

    public interface ISchedulerListener
+    {
+        void JobScheduled(Trigger trigger);
+    
+        void JobUnscheduled(string triggerName, string triggerGroup);
+    
+        void TriggerFinalized(Trigger trigger);
+    
+        void TriggersPaused(string triggerName, string triggerGroup);
+    
+        void TriggersResumed(string triggerName, string triggerGroup);
+    
+        void JobsPaused(string jobName, string jobGroup);
+    
+        void JobsResumed(string jobName, string jobGroup);
+    
+        void SchedulerError(string msg, SchedulerException cause);
+    
+        void SchedulerShutdown();
+    } 
+

ISchedulerListener instances are created and registered in much the same way as the other listener types, +except there is no distinction between global and non-global listeners. Scheduler listeners can be +virtually any object that implements the ISchedulerListener interface.

+ + + diff --git a/documentation/quartz-1.x/tutorial/simpletriggers.html b/documentation/quartz-1.x/tutorial/simpletriggers.html new file mode 100644 index 000000000..4c4abf48f --- /dev/null +++ b/documentation/quartz-1.x/tutorial/simpletriggers.html @@ -0,0 +1,121 @@ + + + + + + Lesson 5: SimpleTrigger | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time, +or at a specific moment in time followed by repeats at a specific interval. Or plainer english, if you want the trigger to +fire at exactly 11:23:54 AM on January 13, 2005, and then fire five more times, every ten seconds.

With this description, you may not find it surprising to find that the properties of a SimpleTrigger include: a start-time, +and end-time, a repeat count, and a repeat interval. All of these properties are exactly what you'd expect them to be, with +only a couple special notes related to the end-time property.

The repeat count can be zero, a positive integer, or the constant value SimpleTrigger.RepeatIndefinitely. +The repeat interval property must be TimeSpan.Zero, or a positive TimeSpan value. +Note that a repeat interval of zero will cause 'repeat count' firings of the trigger to happen concurrently +(or as close to concurrently as the scheduler can manage).

If you're not already familiar with the DateTime class, you may find it helpful for computing your trigger fire-times, +depending on the startTimeUtc (or endTimeUtc) that you're trying to create. The TriggerUtils class is also helpful in this respect.

The EndTimeUtc property (if it is specified) over-rides the repeat count property. This can be useful if you wish to create a trigger +such as one that fires every 10 seconds until a given moment in time - rather than having to compute the number of times it would +repeat between the start-time and the end-time, you can simply specify the end-time and then use a repeat count of RepeatIndefinitely +(you could even specify a repeat count of some huge number that is sure to be more than the number of times the trigger will actually +fire before the end-time arrives).

SimpleTrigger has a few different constructors, but we'll examine this one, and use it in the few examples that follow:

One of SimpleTrigger's Constructors

    public SimpleTrigger(
+        string name,
+        string group,
+        DateTime startTimeUtc,
+        NullableDateTime endTime endTimeUtc,
+        int repeatCount,
+        TimeSpan repeatInterval)
+

SimpleTrigger Example 1 - Create a trigger that fires exactly once, ten seconds from now

    SimpleTrigger trigger = new SimpleTrigger(
+        "myTrigger",
+        null,
+        DateTime.UtcNow.AddSeconds(10),
+        null,
+        0,
+        TimeSpan.Zero);
+

SimpleTrigger Example 2 - Create a trigger that fires immediately, then repeats every 60 seconds, forever

   SimpleTrigger trigger2 = new SimpleTrigger(
+        "myTrigger",
+        null,
+        DateTime.UtcNow,
+        null,
+        SimpleTrigger.RepeatIndefinitely,
+        TimeSpan.FromSeconds(60));
+

SimpleTrigger Example 3 - Create a trigger that fires immediately, then repeats every 10 seconds until 40 seconds from now

TimeSpan.FromSeconds(60));
+     SimpleTrigger trigger = new SimpleTrigger(
+         "myTrigger",
+         "myGroup",
+         DateTime.UtcNow,
+         DateTime.UtcNow.AddSeconds(40),
+         SimpleTrigger.RepeatIndefinitely,
+         TimeSpan.FromSeconds(10));
+

SimpleTrigger Example 4 - Create a trigger that fires on March 17 of the year 2002 at precisely 10:30 am, and repeats 5 times +(for a total of 6 firings) - with a 30 second delay between each firing

     DateTime startTime = new DateTime(2002, 3, 17, 10, 30, 0).ToUniversalTime();
+
+     SimpleTrigger trigger = new SimpleTrigger(
+          "myTrigger",
+          null,
+          startTime,
+          null,
+          5,
+          TimeSpan.FromSeconds(30));
+

Spend some time looking at the other constructors (and property setters) available on SimpleTrigger, so that you can use the +one most convenient to what you want to accomplish.

# SimpleTrigger Misfire Instructions

SimpleTrigger has several instructions that can be used to inform Quartz what it should do when a misfire occurs. +(Misfire situations were introduced in the More About Triggers section of this tutorial). +These instructions are defined as constants on MisfirePolicy.SimpleTrigger (including API documentation describing their behavior). +The instructions include:

Misfire Instruction Constants of SimpleTrigger

  • MisfirePolicy.SimpleTrigger.FireNow
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithExistingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithRemainingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithRemainingCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithExistingCount

You should recall from the earlier lessons that all triggers have the MisfirePolicy.SmartPolicy instruction available for use, +and this instruction is also the default for all trigger types.

If the 'smart policy' instruction is used, SimpleTrigger dynamically chooses between its various MISFIRE instructions, based on the configuration +and state of the given SimpleTrigger instance. The documentation for the SimpleTrigger.UpdateAfterMisfire() method explains the exact details of +this dynamic behavior.

+ + + diff --git a/documentation/quartz-1.x/tutorial/trigger-and-job-listeners.html b/documentation/quartz-1.x/tutorial/trigger-and-job-listeners.html new file mode 100644 index 000000000..5002175e4 --- /dev/null +++ b/documentation/quartz-1.x/tutorial/trigger-and-job-listeners.html @@ -0,0 +1,96 @@ + + + + + + Lesson 7: TriggerListeners and JobListeners | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Listeners are objects that you create to perform actions based on events occuring within the scheduler. +As you can probably guess, TriggerListeners receive events related to triggers, and JobListeners receive events related to jobs.

Trigger-related events include: trigger firings, trigger mis-firings (discussed in the "Triggers" section of this document), +and trigger completions (the jobs fired off by the trigger is finished).

The ITriggerListener Interface

    public interface ITriggerListener
+    {
+         string Name { get; }
+         
+         void TriggerFired(Trigger trigger, JobExecutionContext context);
+         
+         bool VetoJobExecution(Trigger trigger, JobExecutionContext context);
+         
+         void TriggerMisfired(Trigger trigger);
+         
+         void TriggerComplete(Trigger trigger, JobExecutionContext context, int triggerInstructionCode);
+    }
+

Job-related events include: a notification that the job is about to be executed, and a notification when the job has completed execution.

The IJobListener Interface

    public interface IJobListener
+    {
+        string Name { get; }
+    
+        void JobToBeExecuted(JobExecutionContext context);
+    
+        void JobExecutionVetoed(JobExecutionContext context);
+    
+        void JobWasExecuted(JobExecutionContext context, JobExecutionException jobException);
+    } 
+

# Using Your Own Listeners

To create a listener, simply create an object the implements either the ITriggerListener and/or IJobListener interface. +Listeners are then registered with the scheduler during run time, and must be given a name (or rather, they must advertise their own +name via their Name property. Listeners can be registered as either "global" or "non-global". +Global listeners receive events for ALL triggers/jobs, and non-global listeners receive events only for the specific triggers/jobs that +explicitely name the listener in their GetTriggerListenerNames() or GetJobListenerNames() properties.

As described above, listeners are registered with the scheduler during run time, and are NOT stored in the JobStore along with the jobs and triggers. +The jobs and triggers only have the names of the related listeners stored with them. Hence, each time your application runs, the listeners +need to be re-registered with the scheduler.

Adding a JobListener to the Scheduler

scheduler.AddGlobalJobListener(myJobListener);
+

or

scheduler.AddJobListener(myJobListener);
+

Listeners are not used by most users of Quartz.NET, but are handy when application requirements create the need +for the notification of events, without the Job itself explicitly notifying the application.

+ + + diff --git a/documentation/quartz-1.x/tutorial/using-quartz.html b/documentation/quartz-1.x/tutorial/using-quartz.html new file mode 100644 index 000000000..20d0b8d9c --- /dev/null +++ b/documentation/quartz-1.x/tutorial/using-quartz.html @@ -0,0 +1,83 @@ + + + + + + Lesson 1: Using Quartz | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Before you can use the scheduler, it needs to be instantiated (who'd have guessed?). +To do this, you use an implementor of ISchedulerFactory.

Once a scheduler is instantiated, it can be started, placed in stand-by mode, and shutdown. +Note that once a scheduler is shutdown, it cannot be restarted without being re-instantiated. +Triggers do not fire (jobs do not execute) until the scheduler has been started, nor while it is +in the paused state.

Here's a quick snippet of code, that instantiates and starts a scheduler, and schedules a job for execution:

Using Quartz.NET

    // construct a scheduler factory
+    ISchedulerFactory schedFact = new StdSchedulerFactory();
+    
+    // get a scheduler
+    IScheduler sched = schedFact.GetScheduler();
+    sched.Start();
+    
+    // construct job info
+    JobDetail jobDetail = new JobDetail("myJob", null, typeof(HelloJob));
+    // fire every hour
+    Trigger trigger = TriggerUtils.MakeHourlyTrigger();
+    // start on the next even hour
+    trigger.StartTimeUtc = TriggerUtils.GetEvenHourDate(DateTime.UtcNow);
+    trigger.Name = "myTrigger";
+    sched.ScheduleJob(jobDetail, trigger);
+

As you can see, working with Quartz.NET is rather simple. In Lesson 2 we'll give a quick overview of Jobs and Triggers, so that you can more fully understand this example.

+ + + diff --git a/documentation/quartz-2.x/configuration/index.html b/documentation/quartz-2.x/configuration/index.html new file mode 100644 index 000000000..bed168e84 --- /dev/null +++ b/documentation/quartz-2.x/configuration/index.html @@ -0,0 +1,63 @@ + + + + + + Quartz.NET Configuration Reference | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/quartz-2.x/index.html b/documentation/quartz-2.x/index.html new file mode 100644 index 000000000..60eb89e65 --- /dev/null +++ b/documentation/quartz-2.x/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/quartz-2.x/migration-guide.html b/documentation/quartz-2.x/migration-guide.html new file mode 100644 index 000000000..9263ec4eb --- /dev/null +++ b/documentation/quartz-2.x/migration-guide.html @@ -0,0 +1,108 @@ + + + + + + Version Migration Guide | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This document outlines changes needed per version upgrade basis. You need to check the steps for each version you are jumping over. You should also check the complete change log (opens new window).

If you are a new user starting with the latest version, you don't need to follow this guide. Just jump right to the tutorial

# Upgrading to 2.2 from 2.1

# Database schema changes

Database schema has changed to include the scheduled time for fired triggers table. You need to run the migration script:

database\schema_20_to_22_upgrade.sql
+

Make sure you check the scheduler name in the script - the default value of sched_name column is TestScheduler! If you have existing data the scheduler name should correspond to your existing scheduler name in Quartz configuration (quartz.scheduler.instanceName).

# Other

  • SchedulerStarting() method was added to ISchedulerListener interface
  • dbFailureRetryInterval parameter was removed from DirectSchedulerFactory API

There are variations for different database server inside the script. Choose the one suiting you the best.

# Upgrading to 2.1 from 2.0

  • NthIncludedDayTrigger was removed that was supposed to be removed in 2.0
  • There are no Visual Studio 2008 solutions and projects anymore, you need VS2010 or later

# Upgrading to 2.0 from 1.0

# Database schema changes

Database has changed since 1.0 version. You need to run the database migration script:

database\sqlserver_schema_10_to_20_upgrade.sql
+

The script is made for SQL Server, but should work for others. You can adapt the script when needed for your specific database. Always test the migration on non-production server before upgrading production

# API Changes

The most obvious differences with version 2.0 are the significant changes to the API. +These changes have aimed to: modernize the API to use collections and generics, remove ambiguities and redundancies, +hide/remove methods that should not be public to client code, improve separation of concerns, and introduce +a Domain Specific Language (DSL) for working with the core entities (jobs and triggers).

While the API changes are significant, and the usage of the "new way of doing things" is highly encouraged, +there are some formulaic (search-and-replace) techniques that can be used to get 1.x code quickly working with version 2.0. +See the migration guide for more information.

Outline of most significant API changes:

API methods that return (or take as parameters) arrays now return (or take) typed collections. +For example, rather than GetJobGroupNames(): string[] we now have GetJobGroupNames(): IList<string> +Job and Trigger identification is now based on JobKey and TriggerKey. Keys include both a name and group. +Methods which operate on particular jobs/triggers now take keys as the parameter. For example, GetTrigger(TriggerKey key): ITrigger, +rather than GetTrigger(string name, string group): Trigger. +ITrigger is now an interface, rather than a class. Likewise for ISimpleTrigger, ICronTrigger, etc. +New DSL/builder-based API for construction Jobs and Triggers:

IJobDetail job = JobBuilder.Create<SimpleJob>()
+	.WithIdentity("job1", "group1")
+	.Build();
+
+ITrigger trigger = TriggerBuilder.Create()
+	.WithIdentity("trigger1", "group1")
+	.StartAt(DateBuilder.FutureDate(2, IntervalUnit.Hour))
+	.WithSimpleSchedule(x => x.RepeatHourlyForever())
+	.ModifiedByCalendar("holidays")
+	.Build();
+

Methods from TriggerUtils related to easy construction of Dates have been moved to new DateBuilder class, +that can be used with static imports to nicely create Date instances for trigger start and end times, etc.

// build a date for 9:00 am on Halloween
+DateTimeOffset runDate = DateBuilder.DateOf(0, 0, 9, 31, 10);
+
+// build a date 2 hours in the future
+DateTimeOffset myDate = DateBuilder.FutureDate(2, IntervalUnit.Hour);
+

The IStatefulJob interface has been deprecated in favor of new class-level attributes for IJob implementations +(using both attributes produces equivalent to that of the old IStatefulJob interface):

// instructs the scheduler to re-store the Job's JobDataMap contents after execution completes
+[PersistJobDataAfterExecution]
+public class MyJob : IJob
+{
+}
+
// instructs the scheduler to block other instances of the same job (by JobKey) from executing when one already is
+[DisallowConcurrentExecution]
+public class MyJob : IJob
+{
+}
+

Significant changes to usage of JobListener and TriggerListener

  • Removal of distinction between "global" and "non-global" listeners
  • JobDetails and Triggers are no longer configured with a list of names of listeners to notify, instead listeners identify which jobs/triggers they're interested in.
  • Listeners are now assigned a set of Matcher instances - which provide matching rules for jobs/triggers they wish to receive events for.
  • Listeners are now managed through a ListenerManager API, rather than directly with the Scheduler API.

Other changes

  • The SchedulerException class and class hierarchy has been cleaned up.
  • DateIntervalTrigger was renamed to CalendarIntervalTrigger (or more exactly the concrete class is now CalendarIntervalTriggerImpl).
  • The notion (property) of "volatility" of jobs and triggers has been eliminated.
  • New trigger misfire instruction MisfireInstruction.IgnoreMisfirePolicy lets a trigger be configured in such a way +that it is selectively ignored from all misfire handling. In other words, it will fire as soon as it can, with no special handling - +a great option for improving performance particularly with setups that have lots of one-shot (non-repeating) triggers.
  • Trigger's CompareTo() method now correctly relates to its Equals() method, in that it compares the trigger's key, rather than next fire time. +A new Comparator that sorts triggers according to fire time, priority and key was added as Trigger.TriggerTimeComparator.

# New Features

  • Scheduler.Clear() method provides convenient (and dangerous!) way to remove all jobs, triggers and calendars from the scheduler.
  • Scheduler.ScheduleJobs(IDictionary<IJobDetail, IList<ITrigger>> triggersAndJobs, boolean replace) method provides convenient bulk addition of jobs and triggers.
  • Scheduler.UnscheduleJobs(IList<TriggerKey> triggerKeys) method provides convenient bulk unscheduling of jobs.
  • Scheduler.DeleteJobs(IList<JobKey> jobKeys) method provides convenient bulk deletion of jobs (and related triggers).
  • Scheduler.CheckExists(JobKey jobKey) and Scheduler.CheckExists(TriggerKey triggerKey) methods provides convenient way to determine uniqueness of job/trigger keys (as opposed to old have of having to retrieve the job/trigger by name and then check whether the result was null).
  • AdoJobStore now allows one set of tables to be used by multiple distinct scheduler instances
  • AdoJobStore is now capable of storing non-core Trigger implementations without using BLOB columns, through the use of the new TriggerPersistenceDelegate interface, which can (optionally) be implemented by implementers of custom Trigger types.
  • Cron expressions now support the ability to specify an offset for "last day of month" and "last weekday of month" expressions. For examples: "L-3" (three days back from the last of the month) or "L-3W" (nearest weekday to the day three days back from the last day of the month).
  • XML files containing scheduling data now have a way to specify trigger start times as offsets into the future from the time the file is processed (useful for triggers that need to begin firing some time after the application is launched/deployed). +From schema: <xs:element name="start-time-seconds-in-future" type="xs:nonNegativeInteger"/>
  • XML file schema now supports specifying the 'priority' property of triggers.
  • Added DirectoryScanJob to core jobs that ship with Quartz, also added minimum age parameter to pre-existing FileScanJob.

# Miscellaneous

Various performance improvements, including (but not limited to):

  • Ability to batch-acquire triggers that are ready to be fired, which can provide performance improvements for very busy schedulers
  • Methods for batch addition/removal of jobs and triggers (see "New Features")
  • Triggers have a new misfire instruction option, MisfireInstruction.IgnoreMisfirePolicy, which may be useful if you do not require misfire handling for your trigger(s), and want to take advantage of a performance gain
+ + + diff --git a/documentation/quartz-2.x/quick-start.html b/documentation/quartz-2.x/quick-start.html new file mode 100644 index 000000000..534a77f6d --- /dev/null +++ b/documentation/quartz-2.x/quick-start.html @@ -0,0 +1,208 @@ + + + + + + Quartz.NET Quick Start Guide | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Welcome to the Quick Start Guide for Quartz.NET. As you read this guide, expect to see details of:

  • Downloading Quartz.NET
  • Installing Quartz.NET
  • Configuring Quartz to your own particular needs
  • Starting a sample application

# Download and Install

You can either download the zip file or use the NuGet package. NuGet package contains only the binaries needed to run Quartz.NET, zip file comes with source code, samples and Quartz.NET server sample application.

# Zip Archive

Short version: Once you've downloaded Quartz.NET, unzip it somewhere, grab the Quartz.dll and Common.Logging.dll from bin directory and start to use them.

Quartz depends only on single third-party library called Common.Logging (which contains logging abstractions that allow you to use the logging provider that suites you the best). +You need to have Quartz.dll and Commong.Logging.dll beside your app binaries to successfully run Quartz.NET. So just add them as references to your Visual Studio project that uses them. +You can find these dlls from extracted archive from path bin\your-target-framework-version\release\Quartz.

# NuGet Package

Couldn't get any simpler than this. Just fire up Visual Studio (with NuGet installed) and add reference to package Quartz from package manager extension:

  • Right-click on your project's References and choose Manage NuGet Packages...
  • Choose Online category from the left
  • Enter Quartz to the top right search and hit enter
  • Choose Quartz.NET from search results and hit install
  • Done!

or from NuGet Command-Line:

Install-Package Quartz
+

# Configuration

This is the big bit! Quartz.NET is a very configurable library. There are three ways (which are not mutually exclusive) to supply Quartz.NET configuration information:

  • Programmatically via providing NameValueCollection parameter to scheduler factory
  • Via standard youapp.exe.config configuration file using quartz-element
  • quartz.config file in your application's root directory

You can find samples of all these alternatives in the Quartz.NET zip file.

Full documentation of available properties is available in the Quartz Configuration Reference.

To get up and running quickly, a basic quartz.config looks something like this:

quartz.scheduler.instanceName = MyScheduler
+quartz.threadPool.threadCount = 3
+quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
+

Remember to set the Copy to Output Directory on Visual Studio's file property pages to have value Copy always. Otherwise the config will not be seen if it's not in build directory.

The scheduler created by this configuration has the following characteristics:

  • quartz.scheduler.instanceName - This scheduler's name will be "MyScheduler".
  • quartz.threadPool.threadCount - There are 3 threads in the thread pool, which means that a maximum of 3 jobs can be run simultaneously.
  • quartz.jobStore.type - All of Quartz's data, such as details of jobs and triggers, is held in memory (rather than in a database). +Even if you have a database and want to use it with Quartz, I suggest you get Quartz working with the RamJobStore before you open up a whole new dimension by working with a database.

Actually you don't need to define these properties if you don't want to, Quartz.NET comes with sane defaults

# Starting a Sample Application

Now you've downloaded and installed Quartz, it's time to get a sample application up and running. The following code obtains an instance of the scheduler, starts it, then shuts it down:

Program.cs

using System;
+using System.Threading;
+
+using Quartz;
+using Quartz.Impl;
+
+namespace QuartzSampleApplication
+{
+    public class Program
+    {
+        private static void Main(string[] args)
+        {
+            try
+            {
+                // Grab the Scheduler instance from the Factory 
+                IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
+
+                // and start it off
+                scheduler.Start();
+
+                // some sleep to show what's happening
+                Thread.Sleep(TimeSpan.FromSeconds(60));
+
+                // and last shut down the scheduler when you are ready to close your program
+                scheduler.Shutdown();
+            }
+            catch (SchedulerException se)
+            {
+                Console.WriteLine(se);
+            }
+        }
+    }
+}
+

Once you obtain a scheduler using StdSchedulerFactory.GetDefaultScheduler(), your application will not terminate by default until you call scheduler.Shutdown(), because there will be active threads (non-daemon threads).

Now running the program will not show anything. When 10 seconds have passed the program will just terminate. Lets add some logging to console.

# Adding logging

Common.Logging (opens new window) can be configured to use different logging frameworks under the hood; namely Enterprise Library, Log4Net and NLog.

However, to keep things simple for our example we take the simple route and configure logging using code to just log to the console using Common.Logging basic logging mechanism.

Add the following line to the beginning of your Program.cs

Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};
+

# Trying out the application and adding jobs

Now we should get a lot more information when we start the application.

11.1.2014 14:52:04 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz.NET properties loaded from configuration file 'c:\ConsoleApplication1\bin\Debug\quartz.config'
+11.1.2014 14:52:04 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementation for object serializer
+11.1.2014 14:52:04 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
+11.1.2014 14:52:04 [INFO]  Quartz.Core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
+11.1.2014 14:52:04 [INFO]  Quartz.Core.QuartzScheduler - Quartz Scheduler v.2.2.1.400 created.
+11.1.2014 14:52:04 [INFO]  Quartz.Simpl.RAMJobStore - RAMJobStore initialized.
+11.1.2014 14:52:04 [INFO]  Quartz.Core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.1.400) 'MyScheduler' with instanceId 'NON_CLUSTERED'
+  Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
+  NOT STARTED.
+  Currently in standby mode.
+  Number of jobs executed: 0
+  Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 3 threads.
+  Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.
+
+11.1.2014 14:52:04 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler 'MyScheduler' initialized
+11.1.2014 14:52:04 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler version: 2.2.1.400
+11.1.2014 14:52:04 [INFO]  Quartz.Core.QuartzScheduler - Scheduler MyScheduler_$_NON_CLUSTERED started.
+

We need a simple test job to test the functionality, lets create HelloJob that outputs greetings to console.

public class HelloJob : IJob
+{
+	public void Execute(IJobExecutionContext context)
+	{
+		Console.WriteLine("Greetings from HelloJob!");
+	}
+}
+

To do something interesting, you need code just after Start() method, before the Thread.Sleep.

// define the job and tie it to our HelloJob class
+IJobDetail job = JobBuilder.Create<HelloJob>()
+	.WithIdentity("job1", "group1")
+	.Build();
+
+// Trigger the job to run now, and then repeat every 10 seconds
+ITrigger trigger = TriggerBuilder.Create()
+	.WithIdentity("trigger1", "group1")
+	.StartNow()
+	.WithSimpleSchedule(x => x
+		.WithIntervalInSeconds(10)
+		.RepeatForever())
+	.Build();
+
+// Tell quartz to schedule the job using our trigger
+scheduler.ScheduleJob(job, trigger);
+

The complete console application will now look like this

using System;
+using System.Threading;
+
+using Quartz;
+using Quartz.Impl;
+using Quartz.Job;
+
+namespace ConsoleApplication1
+{
+    public class Program
+    {
+        private static void Main(string[] args)
+        {
+            try
+            {
+                Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter {Level = Common.Logging.LogLevel.Info};
+
+                // Grab the Scheduler instance from the Factory 
+                IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
+
+                // and start it off
+                scheduler.Start();
+
+                // define the job and tie it to our HelloJob class
+                IJobDetail job = JobBuilder.Create<HelloJob>()
+                    .WithIdentity("job1", "group1")
+                    .Build();
+
+                // Trigger the job to run now, and then repeat every 10 seconds
+                ITrigger trigger = TriggerBuilder.Create()
+                    .WithIdentity("trigger1", "group1")
+                    .StartNow()
+                    .WithSimpleSchedule(x => x
+                        .WithIntervalInSeconds(10)
+                        .RepeatForever())
+                    .Build();
+
+                // Tell quartz to schedule the job using our trigger
+                scheduler.ScheduleJob(job, trigger);
+
+                // some sleep to show what's happening
+                Thread.Sleep(TimeSpan.FromSeconds(60));
+
+                // and last shut down the scheduler when you are ready to close your program
+                scheduler.Shutdown();
+            }
+            catch (SchedulerException se)
+            {
+                Console.WriteLine(se);
+            }
+
+            Console.WriteLine("Press any key to close the application");
+            Console.ReadKey();
+        }
+    }
+
+    public class HelloJob : IJob
+    {
+        public void Execute(IJobExecutionContext context)
+        {
+            Console.WriteLine("Greetings from HelloJob!");
+        }
+    }
+}
+

Now go have some fun exploring Quartz.NET! You can continue by reading the tutorial.

+ + + diff --git a/documentation/quartz-2.x/tutorial/advanced-enterprise-features.html b/documentation/quartz-2.x/tutorial/advanced-enterprise-features.html new file mode 100644 index 000000000..b468061e8 --- /dev/null +++ b/documentation/quartz-2.x/tutorial/advanced-enterprise-features.html @@ -0,0 +1,70 @@ + + + + + + Lesson 11: Advanced (Enterprise) Features | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Clustering

Clustering currently only works with the AdoJobstore (JobStoreTX). Features include load-balancing and job fail-over (if the JobDetail's "request recovery" flag is set to true).

Enable clustering by setting the "quartz.jobStore.clustered" property to "true". +Each instance in the cluster should use the same copy of the quartz properties. +Exceptions of this would be to use properties that are identical, with the following allowable exceptions: +Different thread pool size, and different value for the "quartz.scheduler.instanceId" property. +Each node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing "AUTO" as the value of this property.

Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly +(the clocks must be within a second of each other). See http://www.boulder.nist.gov/timefreq/service/its.htm +if you are unfamiliar with how to do this.

Never fire-up a non-clustered instance against the same set of tables that any other instance is running against. +You may get serious data corruption, and will definitely experience eratic behavior.

+ + + diff --git a/documentation/quartz-2.x/tutorial/configuration-resource-usage-and-scheduler-factory.html b/documentation/quartz-2.x/tutorial/configuration-resource-usage-and-scheduler-factory.html new file mode 100644 index 000000000..5ad4f2ff3 --- /dev/null +++ b/documentation/quartz-2.x/tutorial/configuration-resource-usage-and-scheduler-factory.html @@ -0,0 +1,94 @@ + + + + + + Lesson 10: Configuration, Resource Usage and SchedulerFactory | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz is architected in modular way, and therefore to get it running, several components need to be "snapped" together. +Fortunately, some helpers exist for making this happen.

The major components that need to be configured before Quartz can do its work are:

  • ThreadPool
  • JobStore
  • DataSources (if necessary)
  • The Scheduler itself

The ThreadPool provides a set of Threads for Quartz to use when executing Jobs. +The more threads in the pool, the greater number of Jobs that can run concurrently. +However, too many threads may bog-down your system. +Most Quartz users find that 5 or so threads are plenty- because they have fewer than 100 jobs at any given time, +the jobs are not generally scheduled to run at the same time, and the jobs are short-lived (complete quickly). +Other users find that they need 10, 15, 50 or even 100 threads - because they have tens-of-thousands +of triggers with various schedules - which end up having an average of between 10 and 100 jobs trying to +execute at any given moment. Finding the right size for your scheduler's pool is completely dependent on +what you're using the scheduler for. There are no real rules, other than to keep the number of threads as +small as possible (for the sake of your machine's resources) - but make sure you have enough for your Jobs to fire on time. +Note that if a trigger's time to fire arrives, and there isn't an available thread, +Quartz will block (pause) until a thread comes available, then the Job will execute - +some number of milliseconds later than it should have. This may even cause the tread to misfire - if +there is no available thread for the duration of the scheduler's configured "misfire threshold".

A IThreadPool interface is defined in the Quartz.Spi namespace, and you can create a IThreadPool implementation in any way you like. +Quartz ships with a simple (but very satisfactory) thread pool named Quartz.Simpl.SimpleThreadPool. +This IThreadPool implementation simply maintains a fixed set of threads in its pool - never grows, never shrinks. +But it is otherwise quite robust and is very well tested - as nearly everyone using Quartz uses this pool.

JobStores and DataSrouces were discussed in Lesson 9 of this tutorial. Worth noting here, is the fact that all JobStores +implement the IJobStore interface - and that if one of the bundled JobStores does not fit your needs, then you can make your own.

Finally, you need to create your Scheduler instance. The Scheduler itself needs to be given a name and handed +instances of a JobStore and ThreadPool.

# StdSchedulerFactory

StdSchedulerFactory is an implementation of the ISchedulerFactory interface. +It uses a set of properties (NameValueCollection) to create and initialize a Quartz Scheduler. +The properties are generally stored in and loaded from a file, but can also be created by your program and handed directly to the factory. +Simply calling getScheduler() on the factory will produce the scheduler, initialize it (and its ThreadPool, JobStore and DataSources), +and return a handle to its public interface.

There are some sample configurations (including descriptions of the properties) in the "docs/config" directory of the Quartz distribution. +You can find complete documentation in the "Configuration" manual under the "Reference" section of the Quartz documentation.

# DirectSchedulerFactory

DirectSchedulerFactory is another SchedulerFactory implementation. It is useful to those wishing to create their Scheduler +instance in a more programatic way. Its use is generally discouraged for the following reasons: (1) it +requires the user to have a greater understanding of what they're doing, and (2) it does not allow for declaritive +configuration - or in other words, you end up hard-coding all of the scheduler's settings.

# Logging

Quartz.NET uses the Common.Logging framework for all of its logging needs. +Quartz does not produce much logging information - generally just some information during initialization, and +then only messages about serious problems while Jobs are executing. In order to "tune" the logging settings +(such as the amount of output, and where the output goes), you need to understand the Commmon.Logging framework, +which is beyond the scope of this document, please refer to Common.Logging Documentation.

+ + + diff --git a/documentation/quartz-2.x/tutorial/crontrigger.html b/documentation/quartz-2.x/tutorial/crontrigger.html new file mode 100644 index 000000000..8e8cc331b --- /dev/null +++ b/documentation/quartz-2.x/tutorial/crontrigger.html @@ -0,0 +1,67 @@ + + + + + + CronTrigger Tutorial | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Introduction

cron is a UNIX tool that has been around for a long time, so its scheduling capabilities are powerful and proven. The CronTrigger class is based on the scheduling capabilities of cron.

CronTrigger uses "cron expressions", which are able to create firing schedules such as: "At 8:00am every Monday through Friday" or "At 1:30am every last Friday of the month".

Cron expressions are powerful, but can be pretty confusing. This tutorial aims to take some of the mystery out of creating a cron expression, giving users a resource which they can visit before having to ask in a forum or mailing list.

# Format

A cron expression is a string comprised of 6 or 7 fields separated by white space. +Fields can contain any of the allowed values, along with various combinations of the allowed special characters for that field. The fields are as follows:

Field Name Mandatory Allowed Values Allowed Special Characters
Seconds YES 0-59 , - * /
Minutes YES 0-59 , - * /
Hours YES 0-23 , - * /
Day of month YES 1-31 , - * ? / L W
Month YES 1-12 or JAN-DEC , - * /
Day of week YES 1-7 or SUN-SAT , - * ? / L #
Year NO empty, 1970-2099 , - * /

So cron expressions can be as simple as this: * * * * ? *

or more complex, like this: 0/5 14,18,3-39,52 * ? JAN,MAR,SEP MON-FRI 2002-2010

# Special characters

    • ("all values") - used to select all values within a field. For example, "" in the minute field means *"every minute".
  • ? ("no specific value") - useful when you need to specify something in one of the two fields in which the character is allowed, but not the other. For example, if I want my trigger to fire on a particular day of the month (say, the 10th), but don't care what day of the week that happens to be, I would put "10" in the day-of-month field, and "?" in the day-of-week field. See the examples below for clarification.
  • - - used to specify ranges. For example, "10-12" in the hour field means "the hours 10, 11 and 12".
  • , - used to specify additional values. For example, "MON,WED,FRI" in the day-of-week field means "the days Monday, Wednesday, and Friday".
  • / - used to specify increments. For example, "0/15" in the seconds field means "the seconds 0, 15, 30, and 45". And "5/15" in the seconds field means "the seconds 5, 20, 35, and 50". You can also specify '/' after the '' character - in this case '' is equivalent to having '0' before the '/'. '1/3' in the day-of-month field means "fire every 3 days starting on the first day of the month".
  • L ("last") - has different meaning in each of the two fields in which it is allowed. For example, the value "L" in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - for example "6L" means "the last friday of the month". You can also specify an offset from the last day of the month, such as "L-3" which would mean the third-to-last day of the calendar month. When using the 'L' option, it is important not to specify lists, or ranges of values, as you'll get confusing/unexpected results.
  • W ("weekday") - used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month". So if the 15th is a Saturday, the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. However if you specify "1W" as the value for day-of-month, and the 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not 'jump' over the boundary of a month's days. The 'W' character can only be specified when the day-of-month is a single day, not a range or list of days. +** The 'L' and 'W' characters can also be combined in the day-of-month field to yield 'LW', which translates to "last weekday of the month".
  • # - used to specify "the nth" XXX day of the month. For example, the value of "6#3" in the day-of-week field means "the third Friday of the month" (day 6 = Friday and "#3" = the 3rd one in the month). Other examples: "2#1" = the first Monday of the month and "4#5" = the fifth Wednesday of the month. Note that if you specify "#5" and there is not 5 of the given day-of-week in the month, then no firing will occur that month. +** The legal characters and the names of months and days of the week are not case sensitive. MON is the same as mon.

# Examples

Here are some full examples:

Expression Meaning
0 0 12 * * ? Fire at 12pm (noon) every day
0 15 10 ? * * Fire at 10:15am every day
0 15 10 * * ? Fire at 10:15am every day
0 15 10 * * ? * Fire at 10:15am every day
0 15 10 * * ? 2005 Fire at 10:15am every day during the year 2005
0 * 14 * * ? Fire every minute starting at 2pm and ending at 2:59pm, every day
0 0/5 14 * * ? Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day
0 0/5 14,18 * * ? Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day
0 0-5 14 * * ? Fire every minute starting at 2pm and ending at 2:05pm, every day
0 10,44 14 ? 3 WED Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.
0 15 10 ? * MON-FRI Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday
0 15 10 15 * ? Fire at 10:15am on the 15th day of every month
0 15 10 L * ? Fire at 10:15am on the last day of every month
0 15 10 L-2 * ? Fire at 10:15am on the 2nd-to-last last day of every month
0 15 10 ? * 6L Fire at 10:15am on the last Friday of every month
0 15 10 ? * 6L Fire at 10:15am on the last Friday of every month
0 15 10 ? * 6L 2002-2005 Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005
0 15 10 ? * 6#3 Fire at 10:15am on the third Friday of every month
0 0 12 1/5 * ? Fire at 12pm (noon) every 5 days every month, starting on the first day of the month.
0 11 11 11 11 ? Fire every November 11th at 11:11am.
  • Pay attention to the effects of '?' and '*' in the day-of-week and day-of-month fields!

# Notes

  • Support for specifying both a day-of-week and a day-of-month value is not complete (you must currently use the '?' character in one of these fields).
  • Be careful when setting fire times between the hours of the morning when "daylight savings" changes occur in your locale (for US locales, this would typically be the hour before and after 2:00 AM - because the time shift can cause a skip or a repeat depending on whether the time moves back or jumps forward. You may find this wikipedia entry helpful in determining the specifics to your locale: +https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world
+ + + diff --git a/documentation/quartz-2.x/tutorial/crontriggers.html b/documentation/quartz-2.x/tutorial/crontriggers.html new file mode 100644 index 000000000..01eee183e --- /dev/null +++ b/documentation/quartz-2.x/tutorial/crontriggers.html @@ -0,0 +1,127 @@ + + + + + + Lesson 6: CronTrigger | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

CronTriggers are often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions, +rather than on the exactly specified intervals of SimpleTrigger.

With CronTrigger, you can specify firing-schedules such as "every Friday at noon", or "every weekday and 9:30 am", +or even "every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday".

Even so, like SimpleTrigger, CronTrigger has a startTime which specifies when the schedule is in force, and an (optional) +endTime that specifies when the schedule should be discontinued.

# Cron Expressions

Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up +of seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:

    1. Seconds
    1. Minutes
    1. Hours
    1. Day-of-Month
    1. Month
    1. Day-of-Week
    1. Year (optional field)

An example of a complete cron-expression is the string "0 0 12 ? * WED" - which means "every Wednesday at 12:00 pm".

Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED") +example could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".

Wild-cards (the '' character) can be used to say "every" possible value of this field. Therefore the '' character in the +"Month" field of the previous example simply means "every month". A '*' in the Day-Of-Week field would obviously mean "every day of the week".

All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers +0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful +about how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings +JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday) +or by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.

The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes, +starting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour, +starting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.

The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify "no specific value". +This is useful when you need to specify something in one of the two fields, but not the other. +See the examples below (and CronTrigger API documentation) for clarification.

The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last", +but it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means +"the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, +it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - +for example "6L" or "FRIL" both mean "the last friday of the month". When using the 'L' option, it is important not to specify lists, +or ranges of values, as you'll get confusing results.

The 'W' is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month".

The '#' is used to specify "the nth" XXX weekday of the month. For example, the value of "6#3" or "FRI#3" in the day-of-week field means "the third Friday of the month".

# Example Cron Expressions

Here are a few more examples of expressions and their meanings - you can find even more in the API documentation for CronTrigger

CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes

"0 0/5 * * * ?"
+

CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).

"10 0/5 * * * ?"
+

CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.

"0 30 10-13 ? * WED,FRI"
+

CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month. +Note that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30

"0 0/30 8-9 5,20 * ?"
+

Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am, +and every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.

# Building CronTriggers

CronTrigger instances are built using TriggerBuilder (for the trigger's main properties) and WithCronSchedule extension method (for the CronTrigger-specific properties).

You can also use CronScheduleBuilder's static methods to create schedules.

Build a trigger that will fire every other minute, between 8am and 5pm, every day:

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 0/2 8-17 * * ?")
+    .ForJob("myJob", "group1")
+    .Build();
+

Build a trigger that will fire daily at 10:42 am:

// we use CronScheduleBuilder's static helper methods here
+trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 42))
+    .ForJob(myJobKey)
+    .Build();
+

or -

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 42 10 * * ?")
+    .ForJob("myJob", "group1")
+    .Build();
+

Build a trigger that will fire on Wednesdays at 10:42 am, in a TimeZone other than the system's default:

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithSchedule(CronScheduleBuilder
+        .WeeklyOnDayAndHourAndMinute(DayOfWeek.Wednesday, 10, 42)
+        .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
+    .ForJob(myJobKey)
+    .Build();
+

or -

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 42 10 ? * WED", x => x
+        .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
+    .ForJob(myJobKey)
+    .Build();
+

# CronTrigger Misfire Instructions

The following instructions can be used to inform Quartz what it should do when a misfire occurs for CronTrigger. +(Misfire situations were introduced in the More About Triggers section of this tutorial). These instructions are defined in as +constants (and API documentation has description for their behavior). The instructions include:

  • MisfireInstruction.IgnoreMisfirePolicy
  • MisfireInstruction.CronTrigger.DoNothing
  • MisfireInstruction.CronTrigger.FireOnceNow

All triggers have the MisfireInstrution.SmartPolicy instruction available for use, and this instruction is also the default for all trigger types. +The 'smart policy' instruction is interpreted by CronTrigger as MisfireInstruction.CronTrigger.FireOnceNow. The API documentation for the +CronTrigger.UpdateAfterMisfire() method explains the exact details of this behavior.

When building CronTriggers, you specify the misfire instruction as part of the cron schedule (via WithCronSchedule extension method):

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 0/2 8-17 * * ?", x => x
+        .WithMisfireHandlingInstructionFireAndProceed())
+    .ForJob("myJob", "group1")
+    .Build();
+
+ + + diff --git a/documentation/quartz-2.x/tutorial/index.html b/documentation/quartz-2.x/tutorial/index.html new file mode 100644 index 000000000..7991614eb --- /dev/null +++ b/documentation/quartz-2.x/tutorial/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET 2.x Tutorial | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/documentation/quartz-2.x/tutorial/job-stores.html b/documentation/quartz-2.x/tutorial/job-stores.html new file mode 100644 index 000000000..3ea96b76a --- /dev/null +++ b/documentation/quartz-2.x/tutorial/job-stores.html @@ -0,0 +1,108 @@ + + + + + + Lesson 9: JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

JobStore's are responsible for keeping track of all the "work data" that you give to the scheduler: +jobs, triggers, calendars, etc. Selecting the appropriate IJobStore implementation for your Quartz scheduler instance is an important step. +Luckily, the choice should be a very easy one once you understand the differences between them. +You declare which JobStore your scheduler should use (and it's configuration settings) in the properties file (or object) that +you provide to the SchedulerFactory that you use to produce your scheduler instance.

Never use a JobStore instance directly in your code. For some reason many people attempt to do this. +The JobStore is for behind-the-scenes use of Quartz itself. You have to tell Quartz (through configuration) which JobStore to use, +but then you should only work with the Scheduler interface in your code.

# RAMJobStore

RAMJobStore is the simplest JobStore to use, it is also the most performant (in terms of CPU time). +RAMJobStore gets its name in the obvious way: it keeps all of its data in RAM. This is why it's lightning-fast, +and also why it's so simple to configure. The drawback is that when your application ends (or crashes) all of +the scheduling information is lost - this means RAMJobStore cannot honor the setting of "non-volatility" on jobs and triggers. +For some applications this is acceptable - or even the desired behavior, but for other applications, this may be disasterous.

Configuring Quartz to use RAMJobStore

quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
+

To use RAMJobStore (and assuming you're using StdSchedulerFactory) you don't need to do anything special. Default configuration +of Quartz.NET uses RAMJobStore as job store implementation.

# ADO.NET Job Store (AdoJobStore)

AdoJobStore is also aptly named - it keeps all of its data in a database via ADO.NET. +Because of this it is a bit more complicated to configure than RAMJobStore, and it also is not as fast. +However, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.

To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use. +You can find table-creation SQL scripts in the "database/dbtables" directory of the Quartz.NET distribution. +If there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB. +One thing to note is that in these scripts, all the the tables start with the prefix "QRTZ_" +such as the tables "QRTZ_TRIGGERS", and "QRTZ_JOB_DETAIL"). This prefix can actually be anything you'd like, as long as you inform AdoJobStore +what the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables, +for multiple scheduler instances, within the same database.

Currently the only option for the internal implementation of job store is JobStoreTX which creates transactions by itself. +This is different from Java version of Quartz where there is also option to choose JobStoreCMT which uses J2EE container +managed transactions.

The last piece of the puzzle is setting up a data source from which AdoJobStore can get connections to your database. +Data sources are defined in your Quartz.NET properties. Data source information contains the connection string +and ADO.NET delegate information.

Configuring Quartz to use JobStoreTx

quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz
+

Next, you need to select a IDriverDelegate implementation for the JobStore to use. +The DriverDelegate is responsible for doing any ADO.NET work that may be needed for your specific database. +StdAdoDelegate is a delegate that uses "vanilla" ADO.NET code (and SQL statements) to do its work. +If there isn't another delegate made specifically for your database, try using this delegate - +special delegates usually have better performance or workarounds for database specific issues. +Other delegates can be found in the "Quartz.Impl.AdoJobStore" namespace, or in its sub-namespaces.

NOTE: Quartz.NET will issue warning if you are using the default StdAdoDelegate as it has poor performance +when you have a lot of triggers to select from. Specific delegates have special SQL to limit result +set length (SQLServerDelegate uses TOP n, PostgreSQLDelegate LIMIT n, OracleDelegate ROWCOUNT() <= n etc.).

Once you've selected your delegate, set its class name as the delegate for AdoJobStore to use.

Configuring AdoJobStore to use a DriverDelegate

quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz
+

Next, you need to inform the JobStore what table prefix (discussed above) you are using.

Configuring AdoJobStore with the Table Prefix

quartz.jobStore.tablePrefix = QRTZ_
+

And finally, you need to set which data source should be used by the JobStore. The named data source must also be defined in your Quartz properties. +In this case, we're specifying that Quartz should use the data source name "myDS" (that is defined elsewhere in the configuration properties).

Configuring AdoJobStore with the name of the data source to use

quartz.jobStore.dataSource = myDS
+

One last thing that is needed for the configuration is to set data source connection string information and database provider. Connection +string is the standard ADO.NET connection which is driver specific. Database provider is an abstraction of database drivers to create +loose coupling between database drivers and Quartz.

Setting Data Source's Connection String And Database Provider

 quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartz;Uid=quartznet;Pwd=quartznet
+ quartz.dataSource.myDS.provider = MySql-50
+

Currently following database providers are supported:

  • SqlServer-20 - SQL Server driver for .NET Framework 2.0
  • OracleODP-20 - Oracle's Oracle Driver
  • OracleODPManaged-1123-40 Oracle's managed driver for Oracle 11
  • OracleODPManaged-1211-40 Oracle's managed driver for Oracle 12
  • MySql-50 - MySQL Connector/.NET v. 5.0 (.NET 2.0)
  • MySql-51 - MySQL Connector/:NET v. 5.1 (.NET 2.0)
  • MySql-65 - MySQL Connector/:NET v. 6.5 (.NET 2.0)
  • SQLite-10 - SQLite ADO.NET 2.0 Provider v. 1.0.56 (.NET 2.0)
  • Firebird-201 - Firebird ADO.NET 2.0 Provider v. 2.0.1 (.NET 2.0)
  • Firebird-210 - Firebird ADO.NET 2.0 Provider v. 2.1.0 (.NET 2.0)
  • Npgsql-20 - PostgreSQL Npgsql

You can and should use latest version of driver if newer is available, just create an assembly binding redirect

If your Scheduler is very busy (i.e. nearly always executing the same number of jobs as the size of the thread pool, then you should +probably set the number of connections in the data source to be the about the size of the thread pool + 1.This is commonly configured +int the ADO.NET connection string - see your driver implementation for details.

The "quartz.jobStore.useProperties" config parameter can be set to "true" (defaults to false) in order to instruct AdoJobStore that all values in JobDataMaps will be strings, +and therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column. This is much safer in the long term, +as you avoid the class versioning issues that there are with serializing your non-String classes into a BLOB.

Configuring AdoJobStore to use strings as JobDataMap values (recommended)

quartz.jobStore.useProperties = true
+
+ + + diff --git a/documentation/quartz-2.x/tutorial/jobs-and-triggers.html b/documentation/quartz-2.x/tutorial/jobs-and-triggers.html new file mode 100644 index 000000000..9d3b51016 --- /dev/null +++ b/documentation/quartz-2.x/tutorial/jobs-and-triggers.html @@ -0,0 +1,107 @@ + + + + + + Lesson 2: Jobs And Triggers | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# The Quartz API

The key interfaces and classes of the Quartz API are:

  • IScheduler - the main API for interacting with the scheduler.
  • IJob - an interface to be implemented by components that you wish to have executed by the scheduler.
  • IJobDetail - used to define instances of Jobs.
  • ITrigger - a component that defines the schedule upon which a given Job will be executed.
  • JobBuilder - used to define/build JobDetail instances, which define instances of Jobs.
  • TriggerBuilder - used to define/build Trigger instances.

In this tutorial for readability's sake following terms are used interchangeably: IScheduler and Scheduler, IJob and Job, IJobDetail and JobDetail, ITrigger and Trigger.

A Scheduler's life-cycle is bounded by it's creation, via a SchedulerFactory and a call to its Shutdown() method. +Once created the IScheduler interface can be used to add, remove, and list Jobs and Triggers, and perform other scheduling-related operations (such as pausing a trigger). +However, the Scheduler will not actually act on any triggers (execute jobs) until it has been started with the Start() method, as shown in Lesson 1.

Quartz provides "builder" classes that define a Domain Specific Language (or DSL, also sometimes referred to as a "fluent interface"). In the previous lesson you saw an example of it, which we present a portion of here again:

	// define the job and tie it to our HelloJob class
+	IJobDetail job = JobBuilder.Create<HelloJob>()
+		.WithIdentity("myJob", "group1") // name "myJob", group "group1"
+		.Build();
+		
+	// Trigger the job to run now, and then every 40 seconds
+	ITrigger trigger = TriggerBuilder.Create()
+		.WithIdentity("myTrigger", "group1")
+		.StartNow()
+		.WithSimpleSchedule(x => x
+			.WithIntervalInSeconds(40)
+			.RepeatForever())            
+		.Build();
+		
+	// Tell quartz to schedule the job using our trigger
+	sched.scheduleJob(job, trigger);
+

The block of code that builds the job definition is using JobBuilder using fluent interface to create the product, IJobDetail. +Likewise, the block of code that builds the trigger is using TriggerBuilder's fluent interface and extension methods that are specific to given trigger type. +Possible schedule extension methods are:

  • WithCalendarIntervalSchedule
  • WithCronSchedule
  • WithDailyTimeIntervalSchedule
  • WithSimpleSchedule

The DateBuilder class contains various methods for easily constructing DateTimeOffset instances for particular points in time (such as a date that represents the next even hour - or in other words 10:00:00 if it is currently 9:43:27).

# Jobs and Triggers

A Job is a class that implements the IJob interface, which has only one simple method:

IJob Interface

    namespace Quartz
+    {
+        public interface IJob
+        {
+            void Execute(JobExecutionContext context);
+        }
+    }
+

When the Job's trigger fires (more on that in a moment), the Execute(..) method is invoked by one of the scheduler's worker threads. +The JobExecutionContext object that is passed to this method provides the job instance with information about its "run-time" environment - +a handle to the Scheduler that executed it, a handle to the Trigger that triggered the execution, the job's JobDetail object, and a few other items.

The JobDetail object is created by the Quartz.NET client (your program) at the time the Job is added to the scheduler. +It contains various property settings for the Job, as well as a JobDataMap, which can be used to store state information for a given instance of your job class. +It is essentially the definition of the job instance, and is discussed in further detail in the next lesson.

Trigger objects are used to trigger the execution (or 'firing') of jobs. When you wish to schedule a job, you instantiate a trigger and 'tune' its properties +to provide the scheduling you wish to have. Triggers may also have a JobDataMap associated with them - this is useful to passing parameters to a +Job that are specific to the firings of the trigger. Quartz ships with a handful of different trigger types, but the most commonly used types +are SimpleTrigger (interface ISimpleTrigger) and CronTrigger (interface ICronTrigger).

SimpleTrigger is handy if you need 'one-shot' execution (just single execution of a job at a given moment in time), or if you need to fire a job at a given time, +and have it repeat N times, with a delay of T between executions. CronTrigger is useful if you wish to have triggering based on calendar-like schedules - +such as "every Friday, at noon" or "at 10:15 on the 10th day of every month."

Why Jobs AND Triggers? Many job schedulers do not have separate notions of jobs and triggers. Some define a 'job' as simply an execution time (or schedule) +along with some small job identifier. Others are much like the union of Quartz's job and trigger objects. While developing Quartz, we decided that it made sense +to create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits.

For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job. +Another benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired, +so that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define +its associated job.

# Identities

Jobs and Triggers are given identifying keys as they are registered with the Quartz scheduler. +The keys of Jobs and Triggers (JobKey and TriggerKey) allow them to be placed into 'groups' which can be useful for organizing your jobs and +triggers into categories such as "reporting jobs" and "maintenance jobs". The name portion of the key of a job or trigger must be unique within the group

  • or in other words, the complete key (or identifier) of a job or trigger is the compound of the name and group.

You now have a general idea about what Jobs and Triggers are, you can learn more about them in +Lesson 3: More About Jobs & JobDetails and Lesson 4: More About Triggers

+ + + diff --git a/documentation/quartz-2.x/tutorial/miscellaneous-features.html b/documentation/quartz-2.x/tutorial/miscellaneous-features.html new file mode 100644 index 000000000..99163aedb --- /dev/null +++ b/documentation/quartz-2.x/tutorial/miscellaneous-features.html @@ -0,0 +1,68 @@ + + + + + + Lesson 12: Miscellaneous Features of Quartz | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Plug-Ins

Quartz provides an interface (ISchedulerPlugin) for plugging-in additional functionality.

Plugins that ship with Quartz to provide various utililty capabilities can be found documented in the Quartz.Plugins namespace. +They provide functionality such as auto-scheduling of jobs upon scheduler startup, logging a history of job and trigger events, +and ensuring that the scheduler shuts down cleanly when the virtual machine exits.

# JobFactory

When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler. +The default JobFactory simply activates a new instance of the job class. You may want to create your own implementation +of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.

See the IJobFactory interface, and the associated Scheduler.SetJobFactory(fact) method.

# 'Factory-Shipped' Jobs

Quartz also provides a number of utility Jobs that you can use in your application for doing things like sending +e-mails and invoking remote objects. These out-of-the-box Jobs can be found documented in the Quartz.Jobs namespace.

+ + + diff --git a/documentation/quartz-2.x/tutorial/more-about-jobs.html b/documentation/quartz-2.x/tutorial/more-about-jobs.html new file mode 100644 index 000000000..dd524d037 --- /dev/null +++ b/documentation/quartz-2.x/tutorial/more-about-jobs.html @@ -0,0 +1,193 @@ + + + + + + Lesson 3: More About Jobs & JobDetails | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

As you saw in Lesson 2, jobs are rather easy to implement. There are just a few more things that you need to understand about +the nature of jobs, about the Execute(..) method of the IJob interface, and about JobDetails.

While a job class that you implement has the code that knows how to do the actual work +of the particular type of job, Quartz.NET needs to be informed about various attributes +that you may wish an instance of that job to have. This is done via the JobDetail class, +which was mentioned briefly in the previous section.

JobDetail instances are built using the JobBuilder class. JobBuilder allows you to describe +your job's details using a fluent interface.

Let's take a moment now to discuss a bit about the 'nature' of jobs and the life-cycle of job instances within Quartz.NET. +First lets take a look back at some of that snippet of code we saw in Lesson 1:

Using Quartz.NET

// define the job and tie it to our HelloJob class
+IJobDetail job = JobBuilder.Create<HelloJob>()
+	.WithIdentity("myJob", "group1")
+	.Build();
+
+// Trigger the job to run now, and then every 40 seconds
+ITrigger trigger = TriggerBuilder.Create()
+  .WithIdentity("myTrigger", "group1")
+  .StartNow()
+  .WithSimpleSchedule(x => x
+	  .WithIntervalInSeconds(40)
+	  .RepeatForever())
+  .Build();
+  
+sched.ScheduleJob(job, trigger);
+

Now consider the job class HelloJob defined as such:

public class HelloJob : IJob
+{
+	public void Execute(IJobExecutionContext context)
+	{
+		Console.WriteLine("HelloJob is executing.");
+	}
+}
+

Notice that we give the scheduler a IJobDetail instance, and that it refers to the job to be executed by simply +providing the job's class. Each (and every) time the scheduler executes the job, it creates a new instance of the +class before calling its Execute(..) method. One of the ramifications of this behavior is the fact that jobs must +have a no-arguement constructor. Another ramification is that it does not make sense to have data-fields defined +on the job class - as their values would not be preserved between job executions.

You may now be wanting to ask "how can I provide properties/configuration for a Job instance?" and "how can I +keep track of a job's state between executions?" The answer to these questions are the same: the key is the JobDataMap, +which is part of the JobDetail object.

# JobDataMap

The JobDataMap can be used to hold any number of (serializable) objects which you wish to have made available +to the job instance when it executes. JobDataMap is an implementation of the IDictionary interface, and has +some added convenience methods for storing and retrieving data of primitive types.

Here's some quick snippets of putting data into the JobDataMap prior to adding the job to the scheduler:

Setting Values in a JobDataMap

// define the job and tie it to our DumbJob class
+IJobDetail job = JobBuilder.Create<DumbJob>()
+	.WithIdentity("myJob", "group1") // name "myJob", group "group1"
+	.UsingJobData("jobSays", "Hello World!")
+	.UsingJobData("myFloatValue", 3.141f)
+	.Build();
+

Here's a quick example of getting data from the JobDataMap during the job's execution:

Getting Values from a JobDataMap

public class DumbJob : IJob
+{
+	public void Execute(JobExecutionContext context)
+	{
+	  JobKey key = context.JobDetail.Key;
+
+	  JobDataMap dataMap = context.JobDetail.JobDataMap;
+
+	  string jobSays = dataMap.GetString("jobSays");
+	  float myFloatValue = dataMap.GetFloat("myFloatValue");
+
+	  Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
+	}
+} 
+

If you use a persistent JobStore (discussed in the JobStore section of this tutorial) you should use some care +in deciding what you place in the JobDataMap, because the object in it will be serialized, and they therefore +become prone to class-versioning problems. Obviously standard .NET types should be very safe, but beyond that, +any time someone changes the definition of a class for which you have serialized instances, +care has to be taken not to break compatibility.

Optionally, you can put AdoJobStore and JobDataMap into a mode where only primitives +and strings can be stored in the map, thus eliminating any possibility of later serialization problems.

If you add properties with set accessor to your job class that correspond to the names of keys in the JobDataMap, +then Quartz's default JobFactory implementation will automatically call those setters when the job is instantiated, +thus preventing the need to explicitly get the values out of the map within your execute method. Note this +functionality is not maintained by default when using a custom JobFactory.

Triggers can also have JobDataMaps associated with them. This can be useful in the case where you have a Job that is stored in the scheduler +for regular/repeated use by multiple Triggers, yet with each independent triggering, you want to supply the Job with different data inputs.

The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge of the JobDataMap +found on the JobDetail and the one found on the Trigger, with the values in the latter overriding any same-named values in the former.

Here's a quick example of getting data from the JobExecutionContext's merged JobDataMap during the job's execution:

public class DumbJob : IJob
+{
+	public void Execute(IJobExecutionContext context)
+	{
+		JobKey key = context.JobDetail.Key;
+
+		JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
+
+		string jobSays = dataMap.GetString("jobSays");
+		float myFloatValue = dataMap.GetFloat("myFloatValue");
+		IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"];
+		state.Add(DateTimeOffset.UtcNow);
+
+		Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
+	}
+}
+

Or if you wish to rely on the JobFactory "injecting" the data map values onto your class, it might look like this instead:

public class DumbJob : IJob
+{
+    public string JobSays { private get; set; }
+    public float FloatValue { private get; set; }
+      
+	public void Execute(IJobExecutionContext context)
+	{
+		JobKey key = context.JobDetail.Key;
+
+		JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
+
+		IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"];
+		state.Add(DateTimeOffset.UtcNow);
+
+		Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + JobSays + ", and val is: " + FloatValue);
+    }
+}
+

You'll notice that the overall code of the class is longer, but the code in the Execute() method is cleaner. +One could also argue that although the code is longer, that it actually took less coding, if the programmer's IDE was used to auto-generate the properties, +rather than having to hand-code the individual calls to retrieve the values from the JobDataMap. The choice is yours.

# Job "Instances"

Many users spend time being confused about what exactly constitutes a "job instance". +We'll try to clear that up here and in the section below about job state and concurrency.

You can create a single job class, and store many 'instance definitions' of it within the scheduler by creating multiple instances of JobDetails

  • each with its own set of properties and JobDataMap - and adding them all to the scheduler.

For example, you can create a class that implements the IJob interface called "SalesReportJob". +The job might be coded to expect parameters sent to it (via the JobDataMap) to specify the name of the sales person that the sales +report should be based on. They may then create multiple definitions (JobDetails) of the job, such as "SalesReportForJoe" +and "SalesReportForMike" which have "joe" and "mike" specified in the corresponding JobDataMaps as input to the respective jobs.

When a trigger fires, the JobDetail (instance definition) it is associated to is loaded, +and the job class it refers to is instantiated via the JobFactory configured on the Scheduler. +The default JobFactory simply calls the default constructor of the job class using Activator.CreateInstance, +then attempts to call setter properties on the class that match the names of keys within the JobDataMap. +You may want to create your own implementation of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.

In "Quartz speak", we refer to each stored JobDetail as a "job definition" or "JobDetail instance", +and we refer to a each executing job as a "job instance" or "instance of a job definition". +Usually if we just use the word "job" we are referring to a named definition, or JobDetail. +When we are referring to the class implementing the job interface, we usually use the term "job type".

# Job State and Concurrency

Now, some additional notes about a job's state data (aka JobDataMap) and concurrency. +There are a couple attributes that can be added to your Job class that affect Quartz's behaviour with respect to these aspects.

DisallowConcurrentExecution is an attribute that can be added to the Job class that tells Quartz not to execute multiple instances +of a given job definition (that refers to the given job class) concurrently. +Notice the wording there, as it was chosen very carefully. In the example from the previous section, if "SalesReportJob" has this attribute, +than only one instance of "SalesReportForJoe" can execute at a given time, but it can execute concurrently with an instance of "SalesReportForMike". +The constraint is based upon an instance definition (JobDetail), not on instances of the job class. +However, it was decided (during the design of Quartz) to have the attribute carried on the class itself, because it does often make a difference to how the class is coded.

PersistJobDataAfterExecution is an attribute that can be added to the Job class that tells Quartz to update the stored copy of +the JobDetail's JobDataMap after the Execute() method completes successfully (without throwing an exception), such that the next +execution of the same job (JobDetail) receives the updated values rather than the originally stored values. +Like the DisallowConcurrentExecution attribute, this applies to a job definition instance, not a job class instance, +though it was decided to have the job class carry the attribute because it does often make a difference to how the class is coded +(e.g. the 'statefulness' will need to be explicitly 'understood' by the code within the execute method).

If you use the PersistJobDataAfterExecution attribute, you should strongly consider also using the DisallowConcurrentExecution attribute, +in order to avoid possible confusion (race conditions) of what data was left stored when two instances of the same job (JobDetail) executed concurrently.

# Other Attributes Of Jobs

Here's a quick summary of the other properties which can be defined for a job instance via the JobDetail object:

  • Durability - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it. +In other words, non-durable jobs have a life span bounded by the existence of its triggers.
  • RequestsRecovery - if a job "requests recovery", and it is executing during the time of a 'hard shutdown' of the scheduler +(i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. +In this case, the JobExecutionContext.Recovering property will return true.

# JobExecutionException

Finally, we need to inform you of a few details of the IJob.Execute(..) method. The only type of exception +that you should throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire contents of the +execute method with a 'try-catch' block. You should also spend some time looking at the documentation for the JobExecutionException, +as your job can use it to provide the scheduler various directives as to how you want the exception to be handled.

+ + + diff --git a/documentation/quartz-2.x/tutorial/more-about-triggers.html b/documentation/quartz-2.x/tutorial/more-about-triggers.html new file mode 100644 index 000000000..1a52702cc --- /dev/null +++ b/documentation/quartz-2.x/tutorial/more-about-triggers.html @@ -0,0 +1,125 @@ + + + + + + Lesson 4: More About Triggers | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Like jobs, triggers are relatively easy to work with, but do contain a variety of customizable options that you need to +be aware of and understand before you can make full use of Quartz.NET. Also, as noted earlier, there are different types of triggers, +that you can select to meet different scheduling needs.

# Common Trigger Attributes

Aside from the fact that all trigger types have TriggerKey properties for tracking their identities, +there are a number of other properties that are common to all trigger types. These common properties are set using the TriggerBuilder +when you are building the trigger definition (examples of that will follow).

Here is a listing of properties common to all trigger types:

  • The JobKey property indicates the identity of the job that should be executed when the trigger fires.
  • The StartTimeUtc property indicates when the trigger's schedule first comes into affect. +The value is a DateTimeOffset object that defines a moment in time on a given calendar date. +For some trigger types, the trigger will actually fire at the start time, for others it simply marks the time that the schedule should start being followed. +This means you can store a trigger with a schedule such as "every 5th day of the month" during January, and if the StartTimeUtc property is set to April 1st, +it will be a few months before the first firing.
  • The EndTimeUtc property indicates when the trigger's schedule should no longer be in effect. +In other words, a trigger with a schedule of "every 5th day of the month" and with an end time of July 1st will fire for it's last time on June 5th.

Other properties, which take a bit more explanation are discussed in the following sub-sections.

# Priority

Sometimes, when you have many Triggers (or few worker threads in your Quartz.NET thread pool), Quartz.NET may not have enough resources to immediately fire all +of the Triggers that are scheduled to fire at the same time. In this case, you may want to control which of your Triggers get first crack at the available Quartz.NET worker threads. +For this purpose, you can set the priority property on a Trigger. If N Triggers are to fire at the same time, but there are only Z worker threads currently available, +then the first Z Triggers with the highest priority will be executed first. If you do not set a priority on a Trigger, then it will use the default priority of 5. +Any integer value is allowed for priority, positive or negative.

Note: Priorities are only compared when triggers have the same fire time. A trigger scheduled to fire at 10:59 will always fire before one scheduled to fire at 11:00.

Note: When a trigger's job is detected to require recovery, its recovery is scheduled with the same priority as the original trigger.

# Misfire Instructions

Another important property of a Trigger is its "misfire instruction". A misfire occurs if a persistent trigger "misses" its firing time because of the scheduler being shutdown, +or because there are no available threads in Quartz.NET's thread pool for executing the job. +The different trigger types have different misfire instructions available to them. +By default they use a 'smart policy' instruction - which has dynamic behavior based on trigger type and configuration. +When the scheduler starts, it searches for any persistent triggers that have misfired, and it then updates each of them based on their individually +configured misfire instructions. When you start using Quartz.NET in your own projects, you should make yourself familiar with the misfire instructions +that are defined on the given trigger types, and explained in their API documentation. More specific information about misfire instructions will be given within +the tutorial lessons specific to each trigger type.

# Calendars

Quartz.NET Calendar objects implementing ICalendar interface can be associated with triggers at the time the trigger is stored in the scheduler. +Calendars are useful for excluding blocks of time from the the trigger's firing schedule. For instance, you could +create a trigger that fires a job every weekday at 9:30 am, but then add a Calendar that excludes all of the business's holidays.

Calendar's can be any serializable objects that implement the ICalendar interface, which looks like this:

namespace Quartz
+{
+	public interface ICalendar
+	{
+		string Description { get; set; }
+
+		ICalendar CalendarBase { set; get; }
+
+		bool IsTimeIncluded(DateTimeOffset timeUtc);
+
+		DateTime GetNextIncludedTimeUtc(DateTimeOffset timeUtc);
+	}
+} 
+

Even though calendars can 'block out' sections of time as narrow as a millisecond, most likely, you'll be interested in +'blocking-out' entire days. As a convenience, Quartz.NET includes the class HolidayCalendar, which does just that.

Calendars must be instantiated and registered with the scheduler via the AddCalendar(..) method. If you use HolidayCalendar, +after instantiating it, you should use its AddExcludedDate(DateTime date) method in order to populate it with the days you wish +to have excluded from scheduling. The same calendar instance can be used with multiple triggers such as this:

Calendar Example

    HolidayCalendar cal = new HolidayCalendar();
+    cal.AddExcludedDate(someDate);
+    
+    sched.AddCalendar("myHolidays", cal, false);
+    
+	ITrigger t = TriggerBuilder.Create()
+		.WithIdentity("myTrigger")
+		.ForJob("myJob")
+		.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
+		.ModifiedByCalendar("myHolidays") // but not on holidays
+		.Build();
+
+	// .. schedule job with trigger
+
+	ITrigger t2 = TriggerBuilder.Create()
+		.WithIdentity("myTrigger2")
+		.ForJob("myJob2")
+		.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
+		.ModifiedByCalendar("myHolidays") // but not on holidays
+		.Build();
+    
+    // .. schedule job with trigger2 
+

The details of the construction/building of triggers will be given in the next couple lessons. +For now, just believe that the code above creates two triggers, each scheduled to fire daily. +However, any of the firings that would have occurred during the period excluded by the calendar will be skipped.

See the Quartz.Impl.Calendar namespace for a number of ICalendar implementations that may suit your needs.

+ + + diff --git a/documentation/quartz-2.x/tutorial/scheduler-listeners.html b/documentation/quartz-2.x/tutorial/scheduler-listeners.html new file mode 100644 index 000000000..1089b123c --- /dev/null +++ b/documentation/quartz-2.x/tutorial/scheduler-listeners.html @@ -0,0 +1,88 @@ + + + + + + Lesson 8: SchedulerListeners | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

SchedulerListeners are much like ITriggerListeners and IJobListeners, except they receive notification of +events within the scheduler itself - not necessarily events related to a specific trigger or job.

Scheduler-related events include: the addition of a job/trigger, the removal of a job/trigger, a serious error +within the scheduler, notification of the scheduler being shutdown, and others.

The ISchedulerListener Interface

public interface ISchedulerListener
+{
+	void JobScheduled(Trigger trigger);
+
+	void JobUnscheduled(string triggerName, string triggerGroup);
+
+	void TriggerFinalized(Trigger trigger);
+
+	void TriggersPaused(string triggerName, string triggerGroup);
+
+	void TriggersResumed(string triggerName, string triggerGroup);
+
+	void JobsPaused(string jobName, string jobGroup);
+
+	void JobsResumed(string jobName, string jobGroup);
+
+	void SchedulerError(string msg, SchedulerException cause);
+
+	void SchedulerShutdown();
+} 
+

SchedulerListeners are registered with the scheduler's ListenerManager. +SchedulerListeners can be virtually any object that implements the ISchedulerListener interface.

Adding a SchedulerListener:

scheduler.ListenerManager.AddSchedulerListener(mySchedListener);
+

Removing a SchedulerListener:

scheduler.ListenerManager.RemoveSchedulerListener(mySchedListener);
+
+ + + diff --git a/documentation/quartz-2.x/tutorial/simpletriggers.html b/documentation/quartz-2.x/tutorial/simpletriggers.html new file mode 100644 index 000000000..f0ba0f543 --- /dev/null +++ b/documentation/quartz-2.x/tutorial/simpletriggers.html @@ -0,0 +1,126 @@ + + + + + + Lesson 5: SimpleTrigger | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time, +or at a specific moment in time followed by repeats at a specific interval. Or plainer english, if you want the trigger to +fire at exactly 11:23:54 AM on January 13, 2005, and then fire five more times, every ten seconds.

With this description, you may not find it surprising to find that the properties of a SimpleTrigger include: a start-time, +and end-time, a repeat count, and a repeat interval. All of these properties are exactly what you'd expect them to be, with +only a couple special notes related to the end-time property.

The repeat count can be zero, a positive integer, or the constant value SimpleTrigger.RepeatIndefinitely. +The repeat interval property must be TimeSpan.Zero, or a positive TimeSpan value. +Note that a repeat interval of zero will cause 'repeat count' firings of the trigger to happen concurrently +(or as close to concurrently as the scheduler can manage).

If you're not already familiar with the DateTime class, you may find it helpful for computing your trigger fire-times, +depending on the startTimeUtc (or endTimeUtc) that you're trying to create.

The EndTimeUtc property (if it is specified) over-rides the repeat count property. This can be useful if you wish to create a trigger +such as one that fires every 10 seconds until a given moment in time - rather than having to compute the number of times it would +repeat between the start-time and the end-time, you can simply specify the end-time and then use a repeat count of RepeatIndefinitely +(you could even specify a repeat count of some huge number that is sure to be more than the number of times the trigger will actually +fire before the end-time arrives).

SimpleTrigger instances are built using TriggerBuilder (for the trigger's main properties) and WithSimpleSchedule extension method (for the SimpleTrigger-specific properties).

Build a trigger for a specific moment in time, with no repeats:

// trigger builder creates simple trigger by default, actually an ITrigger is returned
+ISimpleTrigger trigger = (ISimpleTrigger) TriggerBuilder.Create()
+    .WithIdentity("trigger1", "group1")
+    .StartAt(myStartTime) // some Date 
+    .ForJob("job1", "group1") // identify job with name, group strings
+    .Build();
+

Build a trigger for a specific moment in time, then repeating every ten seconds ten times:

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .StartAt(myTimeToStartFiring) // if a start time is not given (if this line were omitted), "now" is implied
+    .WithSimpleSchedule(x => x
+        .WithIntervalInSeconds(10)
+        .WithRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
+    .ForJob(myJob) // identify job with handle to its JobDetail itself                   
+    .Build();
+
+

Build a trigger that will fire once, five minutes in the future:

trigger = (ISimpleTrigger) TriggerBuilder.Create()
+    .WithIdentity("trigger5", "group1")
+    .StartAt(DateBuilder.FutureDate(5, IntervalUnit.Minute)) // use DateBuilder to create a date in the future
+    .ForJob(myJobKey) // identify job with its JobKey
+    .Build();
+

Build a trigger that will fire now, then repeat every five minutes, until the hour 22:00:

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger7", "group1")
+    .WithSimpleSchedule(x => x
+        .WithIntervalInMinutes(5)
+        .RepeatForever())
+    .EndAt(DateBuilder.DateOf(22, 0, 0))
+    .Build();
+

Build a trigger that will fire at the top of the next hour, then repeat every 2 hours, forever:

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
+    .StartAt(DateBuilder.EvenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
+    .WithSimpleSchedule(x => x
+        .WithIntervalInHours(2)
+        .RepeatForever())
+    // note that in this example, 'forJob(..)' is not called 
+    //  - which is valid if the trigger is passed to the scheduler along with the job  
+    .Build();
+
+scheduler.scheduleJob(trigger, job);
+

Spend some time looking at all of the available methods in the language defined by TriggerBuilder and its extension method WithSimpleSchedule so that you can be familiar with options available to you that may not have been demonstrated in the examples above.

# SimpleTrigger Misfire Instructions

SimpleTrigger has several instructions that can be used to inform Quartz.NET what it should do when a misfire occurs. +(Misfire situations were introduced in the More About Triggers section of this tutorial). +These instructions are defined as constants on MisfirePolicy.SimpleTrigger (including API documentation describing their behavior). +The instructions include:

Misfire Instruction Constants for SimpleTrigger

  • MisfireInstruction.IgnoreMisfirePolicy
  • MisfirePolicy.SimpleTrigger.FireNow
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithExistingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithRemainingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithRemainingCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithExistingCount

You should recall from the earlier lessons that all triggers have the MisfirePolicy.SmartPolicy instruction available for use, +and this instruction is also the default for all trigger types.

If the 'smart policy' instruction is used, SimpleTrigger dynamically chooses between its various MISFIRE instructions, based on the configuration +and state of the given SimpleTrigger instance. The documentation for the SimpleTrigger.UpdateAfterMisfire() method explains the exact details of +this dynamic behavior.

When building SimpleTriggers, you specify the misfire instruction as part of the simple schedule (via SimpleSchedulerBuilder):

trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger7", "group1")
+    .WithSimpleSchedule(x => x
+        .WithIntervalInMinutes(5)
+        .RepeatForever()
+        .WithMisfireHandlingInstructionNextWithExistingCount())
+    .Build();
+
+ + + diff --git a/documentation/quartz-2.x/tutorial/trigger-and-job-listeners.html b/documentation/quartz-2.x/tutorial/trigger-and-job-listeners.html new file mode 100644 index 000000000..de94a26c4 --- /dev/null +++ b/documentation/quartz-2.x/tutorial/trigger-and-job-listeners.html @@ -0,0 +1,98 @@ + + + + + + Lesson 7: TriggerListeners and JobListeners | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Listeners are objects that you create to perform actions based on events occuring within the scheduler. +As you can probably guess, TriggerListeners receive events related to triggers, and JobListeners receive events related to jobs.

Trigger-related events include: trigger firings, trigger mis-firings (discussed in the "Triggers" section of this document), +and trigger completions (the jobs fired off by the trigger is finished).

The ITriggerListener Interface

public interface ITriggerListener
+{
+	 string Name { get; }
+	 
+	 void TriggerFired(ITrigger trigger, IJobExecutionContext context);
+	 
+	 bool VetoJobExecution(ITrigger trigger, IJobExecutionContext context);
+	 
+	 void TriggerMisfired(ITrigger trigger);
+	 
+	 void TriggerComplete(ITrigger trigger, IJobExecutionContext context, int triggerInstructionCode);
+}
+

Job-related events include: a notification that the job is about to be executed, and a notification when the job has completed execution.

The IJobListener Interface

public interface IJobListener
+{
+	string Name { get; }
+
+	void JobToBeExecuted(IJobExecutionContext context);
+
+	void JobExecutionVetoed(IJobExecutionContext context);
+
+	void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException);
+} 
+

# Using Your Own Listeners

To create a listener, simply create an object the implements either the ITriggerListener and/or IJobListener interface. +Listeners are then registered with the scheduler during run time, and must be given a name (or rather, they must advertise their own +name via their Name property.

For your convenience, rather than implementing those interfaces, your class could also extend the class JobListenerSupport or TriggerListenerSupport +and simply override the events you're interested in.

Listeners are registered with the scheduler's ListenerManager along with a Matcher that describes which Jobs/Triggers the listener wants to receive events for.

Listeners are registered with the scheduler during run time, and are NOT stored in the JobStore along with the jobs and triggers. +This is because listeners are typically an integration point with your application. +Hence, each time your application runs, the listeners need to be re-registered with the scheduler.

Adding a JobListener that is interested in a particular job:

scheduler.ListenerManager.AddJobListener(myJobListener, KeyMatcher<JobKey>.KeyEquals(new JobKey("myJobName", "myJobGroup")));
+

Adding a JobListener that is interested in all jobs of a particular group:

scheduler.ListenerManager.AddJobListener(myJobListener, GroupMatcher<JobKey>.GroupEquals("myJobGroup"));
+

Adding a JobListener that is interested in all jobs of two particular groups:

scheduler.ListenerManager.AddJobListener(myJobListener,
+	OrMatcher<JobKey>.Or(GroupMatcher<JobKey>.GroupEquals("myJobGroup"), GroupMatcher<JobKey>.GroupEquals("yourGroup")));
+

Adding a JobListener that is interested in all jobs:

scheduler.ListenerManager.AddJobListener(myJobListener, GroupMatcher<JobKey>.AnyGroup());
+

Listeners are not used by most users of Quartz.NET, but are handy when application requirements create the need +for the notification of events, without the Job itself explicitly notifying the application.

+ + + diff --git a/documentation/quartz-2.x/tutorial/using-quartz.html b/documentation/quartz-2.x/tutorial/using-quartz.html new file mode 100644 index 000000000..84906086e --- /dev/null +++ b/documentation/quartz-2.x/tutorial/using-quartz.html @@ -0,0 +1,89 @@ + + + + + + Lesson 1: Using Quartz | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Before you can use the scheduler, it needs to be instantiated (who'd have guessed?). +To do this, you use an implementor of ISchedulerFactory.

Once a scheduler is instantiated, it can be started, placed in stand-by mode, and shutdown. +Note that once a scheduler is shutdown, it cannot be restarted without being re-instantiated. +Triggers do not fire (jobs do not execute) until the scheduler has been started, nor while it is +in the paused state.

Here's a quick snippet of code, that instantiates and starts a scheduler, and schedules a job for execution:

Using Quartz.NET

    // construct a scheduler factory
+    ISchedulerFactory schedFact = new StdSchedulerFactory();
+    
+    // get a scheduler
+    IScheduler sched = schedFact.GetScheduler();
+    sched.Start();
+    
+	// define the job and tie it to our HelloJob class
+	IJobDetail job = JobBuilder.Create<HelloJob>()
+		.WithIdentity("myJob", "group1")
+		.Build();
+
+	// Trigger the job to run now, and then every 40 seconds
+	ITrigger trigger = TriggerBuilder.Create()
+      .WithIdentity("myTrigger", "group1")
+      .StartNow()
+      .WithSimpleSchedule(x => x
+          .WithIntervalInSeconds(40)
+          .RepeatForever())
+      .Build();
+	  
+    sched.ScheduleJob(job, trigger);
+

As you can see, working with Quartz.NET is rather simple. In Lesson 2 we'll give a quick overview of Jobs and Triggers, so that you can more fully understand this example.

+ + + diff --git a/documentation/quartz-3.x/configuration/reference.html b/documentation/quartz-3.x/configuration/reference.html new file mode 100644 index 000000000..f8ed26499 --- /dev/null +++ b/documentation/quartz-3.x/configuration/reference.html @@ -0,0 +1,186 @@ + + + + + + Quartz.NET Configuration Reference | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Quartz.NET Configuration Reference

By default, StdSchedulerFactory loads a properties file named quartz.config from the "current working directory". +If that fails, then the quartz.config file located (as an embedded resource) in the Quartz dll is loaded. +If you wish to use a file other than these defaults, you must define the system property quartz.properties to point to the file you want.

Alternatively, you can explicitly initialize the factory by calling one of the Initialize(xx) methods before calling GetScheduler() on the StdSchedulerFactory.

Instances of the specified IJobStore, IThreadPool, and other SPI types will be created by name, and then any additional properties specified for them in the config file will be set on the instance by calling an equivalent property set method. +For example if the properties file contains the property quartz.jobStore.myProp = 10 then after the JobStore type has been instantiated, the setter of property MyProp will be called on it. +Type conversion to primitive types (int, long, float, double, boolean, and string) are performed before calling the property’s setter method.

One property can reference another property’s value by specifying a value following the convention of $@other.property.name, for example, to reference the scheduler’s instance name as the value for some other property, you would use $@quartz.scheduler.instanceName.

TIP

You can also use code-based configuration which essentially builds these keys.

# Main Configuration

These properties configure the identification of the scheduler, and various other "top level" settings.

Property Name Required Type Default Value
quartz.scheduler.instanceName no string 'QuartzScheduler'
quartz.scheduler.instanceId no string 'NON_CLUSTERED'
quartz.scheduler.instanceIdGenerator.type no string Quartz.Simpl.SimpleInstanceIdGenerator, Quartz
quartz.scheduler.threadName no string instanceName + '_QuartzSchedulerThread'
quartz.scheduler.makeSchedulerThreadDaemon no boolean false
quartz.scheduler.idleWaitTime no long 30000
quartz.scheduler.dbFailureRetryInterval no long 15000
quartz.scheduler.typeLoadHelper.type no string Quartz.Simpl.SimpleTypeLoadHelper
quartz.scheduler.jobFactory.type no string Quartz.Simpl.PropertySettingJobFactory
quartz.context.key.SOME_KEY no string none
quartz.scheduler.wrapJobExecutionInUserTransaction no boolean false
quartz.scheduler.batchTriggerAcquisitionMaxCount no int 1
quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow no long 0

# quartz.scheduler.instanceName

Can be any string, and the value has no meaning to the scheduler itself - but rather serves as a mechanism for client code to distinguish schedulers when multiple instances are used within the same program. +If you are using the clustering features, you must use the same name for every instance in the cluster that is 'logically' the same scheduler.

# quartz.scheduler.instanceId

Can be any string, but must be unique for all schedulers working as if they are the same 'logical' Scheduler within a cluster. +You may use the value "AUTO" as the instanceId if you wish the Id to be generated for you. +Or the value "SYS_PROP" if you want the value to come from the system property "quartz.scheduler.instanceId".

# quartz.scheduler.instanceIdGenerator.type

Only used if quartz.scheduler.instanceId is set to "AUTO". Defaults to "Quartz.Simpl.SimpleInstanceIdGenerator", +which generates an instance id based upon host name and time stamp. Other InstanceIdGenerator implementations include SystemPropertyInstanceIdGenerator +(which gets the instance id from the system property "quartz.scheduler.instanceId", and HostnameInstanceIdGenerator which uses the local host name (Dns.GetHostEntry(Dns.GetHostName())). +You can also implement the InstanceIdGenerator interface your self.

# quartz.scheduler.threadName

Can be any string that is a valid name for the main scheduler thread. +If this property is not specified, the thread will receive the scheduler’s name ("quartz.scheduler.instanceName") plus an the appended string '_QuartzSchedulerThread'.

# quartz.scheduler.makeSchedulerThreadDaemon

A boolean value ('true' or 'false') that specifies whether the main thread of the scheduler should be a daemon thread or not. +See also the quartz.scheduler.makeSchedulerThreadDaemon property for tuning the DefaultThreadPool if that is the thread pool implementation you are using (which is most likely the case).

# quartz.scheduler.idleWaitTime

Is the amount of time in milliseconds that the scheduler will wait before re-queries for available triggers when the scheduler is otherwise idle. +Normally you should not have to 'tune' this parameter, unless you’re using XA transactions, and are having problems with delayed firings of triggers that should fire immediately. +Values less than 5000 ms are not recommended as it will cause excessive database querying. Values less than 1000 are not legal.

# quartz.scheduler.dbFailureRetryInterval

Is the amount of time in milliseconds that the scheduler will wait between re-tries when it has detected a loss of connectivity within the JobStore (e.g. to the database). +This parameter is obviously not very meaningful when using RamJobStore.

# quartz.scheduler.typeLoadHelper.type

Defaults to the most robust approach, which is to use the "Quartz.Simpl.SimpleTypeLoadHelper" type - which just loads by using Type.GetType().

# quartz.scheduler.jobFactory.type

The type name of the IJobFactory to use. A job factory is responsible for producing instances of IJob implementations. +The default is 'Quartz.Simpl.PropertySettingJobFactory', which simply calls Activator.CreateInstance with given type to produce a new instance each time execution is about to occur. +PropertySettingJobFactory also reflectively sets the job’s properties using the contents of the scheduler context and job and trigger JobDataMaps.

# quartz.context.key.SOME_KEY

Represent a name-value pair that will be placed into the "scheduler context" as strings (see IScheduler.Context). +So for example, the setting "quartz.context.key.MyKey = MyValue" would perform the equivalent of scheduler.Context.Put("MyKey", "MyValue").

# quartz.scheduler.batchTriggerAcquisitionMaxCount

The maximum number of triggers that a scheduler node is allowed to acquire (for firing) at once. Default value is 1. +The larger the number, the more efficient firing is (in situations where there are very many triggers needing to be fired all at once) - +but at the cost of possible imbalanced load between cluster nodes.

If the value of this property is set to > 1, and AdoJobStore is used, then the property "quartz.jobStore.acquireTriggersWithinLock" must be set to "true" to avoid data corruption.

# quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow

The amount of time in milliseconds that a trigger is allowed to be acquired and fired ahead of its scheduled fire time. +Defaults to 0. The larger the number, the more likely batch acquisition of triggers to fire will be able to select and fire more than 1 trigger at a time - +at the cost of trigger schedule not being honored precisely (triggers may fire this amount early).

This may be useful (for performance’s sake) in situations where the scheduler has very large numbers of triggers that need to be fired at or near the same time.

# ThreadPool

Property Name Required Type Default Value
quartz.threadPool.type no string Quartz.Simpl.DefaultThreadPool
quartz.threadPool.maxConcurrency no int 10

# quartz.threadPool.type

Is the name of the ThreadPool implementation you wish to use. +The thread pool that ships with Quartz is "Quartz.Simpl.DefaultThreadPool", and should meet the needs of nearly every user.

It has very simple behavior and is very well tested. It dispatches tasks to .NET task queue and ensures that configured max amount of concurrent tasks limit is obeyed. +You should study CLR's managed thread pool (opens new window) if you want to fine-tune thread pools on CLR level.

# quartz.threadPool.maxConcurrency

This is the number of concurrent tasks that can be dispatched to CLR thread pool. +If you only have a few jobs that fire a few times a day, then 1 tasks is plenty! +If you have tens of thousands of jobs, with many firing every minute, then you probably want a max concurrency count more like 50 or 100 (this highly depends on the nature of the work that your jobs perform, and your systems resources!). +Also note CLR thread pool configuration separate from Quartz itself.

# Custom ThreadPools

If you use your own implementation of a thread pool, you can have properties set on it reflectively simply by naming the property as thus:

Setting Properties on a Custom ThreadPool

quartz.threadPool.type = MyLibrary.FooThreadPool, MyLibrary
+quartz.threadPool.somePropOfFooThreadPool = someValue
+

# Listeners

Global listeners can be instantiated and configured by StdSchedulerFactory, or your application can do it itself at runtime, and then register the listeners with the scheduler. +"Global" listeners listen to the events of every job/trigger rather than just the jobs/triggers that directly reference them.

Configuring listeners through the configuration file consists of giving then a name, and then specifying the type name, and any other properties to be set on the instance. +The type must have a no-arg constructor, and the properties are set reflectively. Only primitive data type values (including strings) are supported.

Thus, the general pattern for defining a "global" TriggerListener is:

Configuring a Global TriggerListener

quartz.triggerListener.NAME.type = MyLibrary.MyListenerType, MyLibrary
+quartz.triggerListener.NAME.propName = propValue
+quartz.triggerListener.NAME.prop2Name = prop2Value
+

And the general pattern for defining a "global" JobListener is:

Configuring a Global JobListener

quartz.jobListener.NAME.type = MyLibrary.MyListenerType, MyLibrary
+quartz.jobListener.NAME.propName = propValue
+quartz.jobListener.NAME.prop2Name = prop2Value
+

# Plug-Ins

Like listeners configuring plugins through the configuration file consists of giving then a name, and then specifying the type name, and any other properties to be set on the instance. The type must have a no-arg constructor, and the properties are set reflectively. Only primitive data type values (including Strings) are supported.

Thus, the general pattern for defining a plug-in is:

Configuring a Plugin

quartz.plugin.NAME.type = MyLibrary.MyPluginType, MyLibrary
+quartz.plugin.NAME.propName = propValue
+quartz.plugin.NAME.prop2Name = prop2Value
+

There are several plugins that come with Quartz, that can be found in the Quartz.Plugins (opens new window) package. +Example of configuring a few of them are as follows:

# Sample configuration of Logging Trigger History Plugin

The logging trigger history plugin catches trigger events (it is also a trigger listener) and logs then with logging infrastructure.

Sample configuration of Logging Trigger History Plugin

quartz.plugin.triggHistory.type = Quartz.Plugin.History.LoggingTriggerHistoryPlugin, Quartz.Plugins
+quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4:HH:mm:ss MM/dd/yyyy}
+quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4:HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
+

# Sample configuration of XML Scheduling Data Processor Plugin

Job initialization plugin reads a set of jobs and triggers from an XML file, and adds them to the scheduler during initialization. It can also delete exiting data.

Sample configuration of JobInitializationPlugin

quartz.plugin.jobInitializer.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins
+quartz.plugin.jobInitializer.fileNames = data/my_job_data.xml
+quartz.plugin.jobInitializer.failOnFileNotFound = true
+

The XML schema definition for the file can be found here (opens new window).

# Sample configuration of Shutdown Hook Plugin

The shutdown-hook plugin catches the event of the CLR terminating, and calls shutdown on the scheduler.

Sample configuration of ShutdownHookPlugin

quartz.plugin.shutdownhook.type = Quartz.Plugin.Management.ShutdownHookPlugin, Quartz.Plugins
+quartz.plugin.shutdownhook.cleanShutdown = true
+

# Sample configuration of Job Interrupt Monitor Plugin

This plugin catches the event of job running for a long time (more than the configured max time) and tells the scheduler to "try" interrupting it if enabled. +Plugin defaults to signaling interrupt after 5 minutes, but the default van be configured to something different, value is in milliseconds in configuration.

Sample configuration of JobInterruptMonitorPlugin

quartz.plugin.jobAutoInterrupt.type = Quartz.Plugin.Interrupt.JobInterruptMonitorPlugin, Quartz.Plugins
+quartz.plugin.jobAutoInterrupt.defaultMaxRunTime = 3000000
+

# Remoting Server and Client

WARNING

Remoting only works with .NET Full Framework. It's also considered unsafe.

Property Name Required Type Default Value
quartz.scheduler.exporter.type yes string
quartz.scheduler.exporter.port yes int
quartz.scheduler.exporter.bindName no string 'QuartzScheduler'
quartz.scheduler.exporter.channelType no string 'tcp'
quartz.scheduler.exporter.channelName no string 'http'
quartz.scheduler.exporter.typeFilterLevel no string 'Full'
quartz.scheduler.exporter.rejectRemoteRequests no boolean false

If you want the Quartz Scheduler to export itself via remoting as a server then set the 'quartz.scheduler.exporter.type' to "Quartz.Simpl.RemotingSchedulerExporter, Quartz".

# quartz.scheduler.exporter.type

The type of ISchedulerExporter, currently only "Quartz.Simpl.RemotingSchedulerExporter, Quartz" is supported.

# quartz.scheduler.exporter.port

The port to listen to.

# quartz.scheduler.exporter.bindName

Name to use when binding to remoting infrastructure.

# quartz.scheduler.exporter.channelType

Either 'tcp' or 'http', TCP is more performant.

# quartz.scheduler.exporter.channelName

Channel name to use when binding to remoting infrastructure.

# quartz.scheduler.exporter.typeFilterLevel

Low

The low deserialization level for .NET Framework remoting. It supports types associated with basic remoting functionality

Full

The full deserialization level for .NET Framework remoting. It supports all types that remoting supports in all situations

# quartz.scheduler.exporter.rejectRemoteRequests

A boolean value (true or false) that specifies whether to refuse requests from other computers. Specifying true allows only remoting calls from the local computer.

# RAMJobStore

RAMJobStore is used to store scheduling information (job, triggers and calendars) within memory. RAMJobStore is fast and lightweight, but all scheduling information is lost when the process terminates.

RAMJobStore is selected by setting the quartz.jobStore.type property as such:

Setting The Scheduler’s JobStore to RAMJobStore

quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
+

RAMJobStore can be tuned with the following properties:

Property Name Required Type Default Value
quartz.jobStore.misfireThreshold no int 60000

# quartz.jobStore.misfireThreshold

The number of milliseconds the scheduler will 'tolerate' a trigger to pass its next-fire-time by, before being considered "misfired". The default value (if you don’t make an entry of this property in your configuration) is 60000 (60 seconds).

# JobStoreTX (ADO.NET)

AdoJobStore is used to store scheduling information (job, triggers and calendars) within a relational database. +There are actually two seperate AdoJobStore implementations that you can select between, depending on the transactional behaviour you need.

JobStoreTX manages all transactions itself by calling Commit() (or Rollback()) on the database connection after every action (such as the addition of a job). +This is the job store you should normally be using unless you want to integrate to some transaction-aware framework.

The JobStoreTX is selected by setting the quartz.jobStore.type property as such:

Setting The Scheduler’s JobStore to JobStoreTX

quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz
+

JobStoreTX can be tuned with the following properties:

Property Name Required Type Default Value
quartz.jobStore.driverDelegateType yes string null
quartz.jobStore.dataSource yes string null
quartz.jobStore.tablePrefix no string "QRTZ_"
quartz.jobStore.useProperties no boolean false
quartz.jobStore.misfireThreshold no int 60000
quartz.jobStore.clustered no boolean false
quartz.jobStore.clusterCheckinInterval no long 15000
quartz.jobStore.maxMisfiresToHandleAtATime no int 20
quartz.jobStore.selectWithLockSQL no string "SELECT * FROM {0}LOCKS WHERE SCHED_NAME = {1} AND LOCK_NAME = ? FOR UPDATE"
quartz.jobStore.txIsolationLevelSerializable no boolean false
quartz.jobStore.acquireTriggersWithinLock no boolean false (or true - see doc below)
quartz.jobStore.lockHandler.type no string null
quartz.jobStore.driverDelegateInitString no string null

# quartz.jobStore.driverDelegateType

Driver delegates understand the particular 'dialects' of varies database systems. Possible built-in choices include:

  • Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz - default when no specific implementation available
  • Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz - for Microsoft SQL Server
  • Quartz.Impl.AdoJobStore.PostgreSQLDelegate, Quartz
  • Quartz.Impl.AdoJobStore.OracleDelegate, Quartz
  • Quartz.Impl.AdoJobStore.SQLiteDelegate, Quartz
  • Quartz.Impl.AdoJobStore.MySQLDelegate, Quartz

# quartz.jobStore.dataSource

The value of this property must be the name of one the DataSources defined in the configuration properties file.

# quartz.jobStore.tablePrefix

AdoJobStore’s "table prefix" property is a string equal to the prefix given to Quartz’s tables that were created in your database. +You can have multiple sets of Quartz’s tables within the same database if they use different table prefixes.

Including schema name in tablePrefix

For backing databases that support schemas (such as Microsoft SQL Server), you may use the tablePrefix to include the schema name. i.e. for a schema named foo the prefix could be set as:

[foo].QRTZ_
+

Note: Any database table create scripts that were run with an explicit schema (such as dbo), will need to be modified to reflect this configuration.

# quartz.jobStore.useProperties

The "use properties" flag instructs AdoJobStore that all values in JobDataMaps will be strings, and therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column. +This is can be handy, as you avoid the type versioning issues that can arise from serializing your non-string types into a BLOB.

# quartz.jobStore.misfireThreshold

The number of milliseconds the scheduler will 'tolerate' a trigger to pass its next-fire-time by, before being considered "misfired". +The default value (if you don’t make an entry of this property in your configuration) is 60000 (60 seconds).

# quartz.jobStore.clustered

Set to "true" in order to turn on clustering features. +This property must be set to "true" if you are having multiple instances of Quartz use the same set of database tables…​ otherwise you will experience havoc. +See the configuration docs for clustering for more information.

# quartz.jobStore.clusterCheckinInterval

Set the frequency (in milliseconds) at which this instance "checks-in"* with the other instances of the cluster. Affects the quickness of detecting failed instances.

# quartz.jobStore.maxMisfiresToHandleAtATime

The maximum number of misfired triggers the job store will handle in a given pass. +Handling many (more than a couple dozen) at once can cause the database tables to be locked long enough that the performance of firing other (not yet misfired) triggers may be hampered.

# quartz.jobStore.selectWithLockSQL

Must be a SQL string that selects a row in the "LOCKS" table and places a lock on the row. If not set, the default is "SELECT * FROM {0}LOCKS WHERE SCHED_NAME = {1} AND LOCK_NAME = ? FOR UPDATE", which works for most databases. +The "{0}" is replaced during run-time with the TABLE_PREFIX that you configured above. +The "{1}" is replaced with the scheduler’s name.

# quartz.jobStore.txIsolationLevelSerializable

A value of "true" tells Quartz (when using JobStoreTX or CMT) to set transction level to serialize on ADO.NET connections. +This can be helpful to prevent lock timeouts with some databases under high load, and "long-lasting" transactions.

# quartz.jobStore.acquireTriggersWithinLock

Whether or not the acquisition of next triggers to fire should occur within an explicit database lock. +This was once necessary (in previous versions of Quartz) to avoid dead-locks with particular databases, but is no longer considered necessary, hence the default value is "false".

If "quartz.scheduler.batchTriggerAcquisitionMaxCount" is set to > 1, and AdoJobStore is used, then this property must be set to "true" to avoid data corruption +(as of Quartz 2 "true" is now the default if batchTriggerAcquisitionMaxCount is set > 1).

# quartz.jobStore.lockHandler.type

The type name to be used to produce an instance of a Quartz.Impl.AdoJobStore.ISemaphore to be used for locking control on the job store data. +This is an advanced configuration feature, which should not be used by most users.

By default, Quartz will select the most appropriate (pre-bundled) Semaphore implementation to use.

# Customizing StdRowLockSemaphore

If you explicitly choose to use this DB Semaphore, you can customize it further on how frequent to poll for DB locks.

Example of Using a Custom StdRowLockSemaphore Implementation

quartz.jobStore.lockHandler.type = Quartz.Impl.AdoJobStore.StdRowLockSemaphore
+quartz.jobStore.lockHandler.maxRetry = 7     # Default is 3
+quartz.jobStore.lockHandler.retryPeriod = 3000  # Default is 1000 millis
+

# quartz.jobStore.driverDelegateInitString

A pipe-delimited list of properties (and their values) that can be passed to the DriverDelegate during initialization time.

The format of the string is as such:

settingName=settingValue|otherSettingName=otherSettingValue|...

The StdAdoDelegate and all of its descendants (all delegates that ship with Quartz) support a property called 'triggerPersistenceDelegateTypes' which can be set to a comma-separated list of types that implement the ITriggerPersistenceDelegate interface for storing custom trigger types. +See the implementations SimplePropertiesTriggerPersistenceDelegateSupport and SimplePropertiesTriggerPersistenceDelegateSupport for examples of writing a persistence delegate for a custom trigger.

# DataSources (ADO.NET JobStores)

If you’re using AdoJobstore, you’ll be needing a DataSource for its use (or two DataSources, if you’re using JobStoreCMT).

Each DataSource you define (typically one or two) must be given a name, and the properties you define for each must contain that name, as shown below. The DataSource’s "NAME" can be anything you want, and has no meaning other than being able to identify it when it is assigned to the AdoJobStore.

Quartz-created DataSources are defined with the following properties:

Property Name Required Type Default Value
quartz.dataSource.NAME.provider yes string
quartz.dataSource.NAME.connectionString string
quartz.dataSource.NAME.connectionStringName string
quartz.dataSource.NAME.connectionProvider.type string

# quartz.dataSource.NAME.provider

Currently following database providers are supported:

  • SqlServer - Microsoft SQL Server
  • OracleODP - Oracle's Oracle Driver
  • OracleODPManaged - Oracle's managed driver for Oracle 11
  • MySql - MySQL Connector/.NET
  • SQLite - SQLite ADO.NET Provider
  • SQLite-Microsoft - Microsoft SQLite ADO.NET Provider
  • Firebird - Firebird ADO.NET Provider
  • Npgsql - PostgreSQL Npgsql

# quartz.dataSource.NAME.connectionString

ADO.NET connection string to use. You can skip this if you are using connectionStringName below.

# quartz.dataSource.NAME.connectionStringName

Connection string name to use. Defined either in app.config or appsettings.json.

# quartz.dataSource.NAME.connectionProvider.type

Allows you to define a custom connection provider implementing IDbProvider interface.

Example of a Quartz-defined DataSource

quartz.dataSource.myDS.provider = SqlServer
+quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartznet;User Id=quartznet;Password=quartznet;
+

# Clustering

Quartz’s clustering features bring both high availability and scalability to your scheduler via fail-over and load balancing functionality.

Clustering currently only works with the AdoJobstore (JobStoreTX or JobStoreCMT), and essentially works by having each node of the cluster share the same database.

Load-balancing occurs automatically, with each node of the cluster firing jobs as quickly as it can. When a trigger’s firing time occurs, the first node to acquire it (by placing a lock on it) is the node that will fire it.

Only one node will fire the job for each firing. +What I mean by that is, if the job has a repeating trigger that tells it to fire every 10 seconds, then at 12:00:00 exactly one node will run the job, and at 12:00:10 exactly one node will run the job, etc. +It won’t necessarily be the same node each time - it will more or less be random which node runs it. +The load balancing mechanism is near-random for busy schedulers (lots of triggers) but favors the same node for non-busy (e.g. few triggers) schedulers.

Fail-over occurs when one of the nodes fails while in the midst of executing one or more jobs. When a node fails, the other nodes detect the condition and identify the jobs in the database that were in progress within the failed node. +Any jobs marked for recovery (with the "requests recovery" property on the JobDetail) will be re-executed by the remaining nodes. Jobs not marked for recovery will simply be freed up for execution at the next time a related trigger fires.

The clustering feature works best for scaling out long-running and/or cpu-intensive jobs (distributing the work-load over multiple nodes). +If you need to scale out to support thousands of short-running (e.g 1 second) jobs, consider partitioning the set of jobs by using multiple distinct schedulers (including multiple clustered schedulers for HA). +The scheduler makes use of a cluster-wide lock, a pattern that degrades performance as you add more nodes (when going beyond about three nodes - depending upon your database’s capabilities, etc.).

Enable clustering by setting the quartz.jobStore.clustered property to "true". Each instance in the cluster should use the same copy of the quartz.properties file. +Exceptions of this would be to use properties files that are identical, with the following allowable exceptions: Different thread pool size, and different value for the quartz.scheduler.instanceId property. +Each node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing "AUTO" as the value of this property. +See the info about the configuration properties of AdoJobStore for more information.

WARNING

Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly (the clocks must be within a second of each other). +See https://www.nist.gov/pml/time-and-frequency-division/services/internet-time-service-its (opens new window) if you are unfamiliar with how to do this.

WARNING

Never start (scheduler.Start()) a non-clustered instance against the same set of database tables that any other instance is running (Start()ed) against. +You may get serious data corruption, and will definitely experience erratic behavior.

WARNING

Monitor and ensure that your nodes have enough CPU resources to complete jobs. +When some nodes are in 100% CPU, they may be unable to update the job store and other nodes can consider these jobs lost and recover them by re-running.

Example Properties For A Clustered Scheduler

#============================================================================
+# Configure Main Scheduler Properties
+#============================================================================
+
+quartz.scheduler.instanceName = MyClusteredScheduler
+quartz.scheduler.instanceId = AUTO
+
+#============================================================================
+# Configure ThreadPool
+#============================================================================
+
+quartz.threadPool.type = Quartz.Simpl.DefaultThreadPool, Quartz
+quartz.threadPool.threadCount = 25
+quartz.threadPool.threadPriority = 5
+
+#============================================================================
+# Configure JobStore
+#============================================================================
+
+quartz.jobStore.misfireThreshold = 60000
+
+quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX
+quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.SqlServerDelegate
+quartz.jobStore.useProperties = true
+quartz.jobStore.dataSource = myDS
+quartz.jobStore.tablePrefix = QRTZ_
+
+quartz.jobStore.clustered = true
+quartz.jobStore.clusterCheckinInterval = 20000
+
+#============================================================================
+# Configure Datasources
+#============================================================================
+
+quartz.dataSource.myDS.provider = SqlServer
+quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartznet;User Id=quartznet;Password=quartznet;
+
+ + + diff --git a/documentation/quartz-3.x/index.html b/documentation/quartz-3.x/index.html new file mode 100644 index 000000000..330da82c5 --- /dev/null +++ b/documentation/quartz-3.x/index.html @@ -0,0 +1,55 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/quartz-3.x/migration-guide.html b/documentation/quartz-3.x/migration-guide.html new file mode 100644 index 000000000..00970f133 --- /dev/null +++ b/documentation/quartz-3.x/migration-guide.html @@ -0,0 +1,95 @@ + + + + + + Version Migration Guide | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

This document outlines changes needed per version upgrade basis. You need to check the steps for each version you are jumping over. You should also check the complete change log (opens new window).

TIP

If you are a new user starting with the latest version, you don't need to follow this guide. Just jump right to the tutorial

Quartz jumped to async/await world and added support for .NET Core with 3.0 release so most significant changes +can be found on APIs and functionality available depending on whether you target full .NET Framework or the .NET Core.

# Packaging changes

Quartz NuGet package was split to more specific packages.

Check that you reference the required NuGet packages and that your configuration references also the correct assembly.

# Database schema changes

2.6 schema should work with 3.0 with no changes.

# Migrating HolidayCalendar binary format

If you have HolidayCalendars stored in database in binary format (just stored with AdoJobStore). You need to first load them with Quartz 2.4 or later 2.x version and then re-store them. +This will make the serialization use format that is not dependant on precense of C5 library.

# Thread pool changes

  • SimpleThreadPool was removed altogether and it's now a synonym for DefaultThreadPool
  • Jobs are now ran in CLR thread pool
  • ThreadCount parameter still limits how many items will be queued at most to CLR thread pool
  • Thread priority is no longer supported, you need to remove threadPriority parameter

# API Changes

Scheduler and job API methods now are based on Tasks. This reflects how you define your jobs and operate with scheduler.

# Scheduler

You now need to make sure that you have proper awaits in place when you operate with the scheduler:

// operating with scheduler is now Task-based and requires appropriate awaits
+await scheduler.ScheduleJob(job, trigger);
+await scheduler.Start();
+await scheduler.Shutdown(waitForJobsToComplete: true);
+

# Jobs

Job's Execute method now returns a Task and can easily contain async code:

// Jobs now return tasks from their Execute methods
+public class MyJob : IJob
+{
+    public async Task Execute(IJobExecutionContext context)
+    {
+        // dummy 1ms sleep
+        await Task.Delay(1);
+    }
+}
+

If you don't have any async'ness in your job, you can just return Task.CompletedTask at the end of Execute method (available from .NET 4.6 onwards).

# IInterruptableJob

IInterruptableJob interface has been removed. You need to check for IJobExecutionContext'sCancellationToken.IsCancellationRequested to determine whether job interruption has been requested.

# IStatefulJob

IStatefulJob interface that was obsoleted in 2.x has been removed, you should use DisallowConcurrentExecution and PersistJobDataAfterExecution attributes to achieve your goal.

# Other APIs

If you have created custom implementations of services used by Quartz, you're going to need to adapt your code to be async-based.

# Job store serialization configuration changes

You need to now explicitly state whether you want to use binary or json serialization if you are using persistent job store (AdoJobStore) when you configure your scheduler.

  • For existing setups you should use the old binary serialization to ensure things work like before (see Quartz.Serialization.Json documentation for migration path)
  • For new projects the JSON serialization is recommended as it should be marginally faster and more robust as it's not dealing with binary versioning issues
  • JSON is more secure and generally the way to use moving forward

If you choose to go with JSON serialization, remember to add NuGet package reference Quartz.Serialization.Json (opens new window) to your project.

Configuring binary serialization strategy:

var properties = new NameValueCollection
+{
+	["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
+	// "binary" is alias for "Quartz.Simpl.BinaryObjectSerializer, Quartz" 
+	["quartz.serializer.type"] = "binary"
+};
+ISchedulerFactory sf = new StdSchedulerFactory(properties);
+

Configuring JSON serialization strategy (recommended):

var properties = new NameValueCollection
+{
+	["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
+	// "json" is alias for "Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json" 
+	["quartz.serializer.type"] = "json"
+};
+ISchedulerFactory sf = new StdSchedulerFactory(properties);
+

# Simplified job store provider names

ADO.NET provider names have been simplified, the provider names are without version, e.g. SqlServer-20 => SqlServer. They are now bound to whatever version that can be loaded.

# C5 Collections

C5 Collections are no longer ILMerged inside Quartz, .NET 4.5 offers the needed collections.

# Logging

Common.Logging has been replaced with LibLog (opens new window) to reduce dependencies to none. LibLog should automatically detect your logging framework of choice if it's supported.

# Remoting

Remoting is currently only supported when running on full framework version.

+ + + diff --git a/documentation/quartz-3.x/packages/aspnet-core-integration.html b/documentation/quartz-3.x/packages/aspnet-core-integration.html new file mode 100644 index 000000000..e508d4da1 --- /dev/null +++ b/documentation/quartz-3.x/packages/aspnet-core-integration.html @@ -0,0 +1,80 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.AspNetCore (opens new window) +provides integration with ASP.NET Core hosted services (opens new window).

TIP

If you only need the generic host, generic host integration might suffice.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.AspNetCore
+

# Using

You can add Quartz configuration by invoking an extension method AddQuartzServer on IServiceCollection. +This will add a hosted quartz server into ASP.NET Core process that will be started and stopped based on applications lifetime.

TIP

See Quartz.Extensions.DependencyInjection documentation to learn more about configuring Quartz scheduler, jobs and triggers.

Example Startup.ConfigureServices configuration

public void ConfigureServices(IServiceCollection services)
+{
+    services.AddQuartz(q =>
+    {
+        // base quartz scheduler, job and trigger configuration
+    });
+
+    // ASP.NET Core hosting
+    services.AddQuartzServer(options =>
+    {
+        // when shutting down we want jobs to complete gracefully
+        options.WaitForJobsToComplete = true;
+    });
+}
+
+ + + diff --git a/documentation/quartz-3.x/packages/hosted-services-integration.html b/documentation/quartz-3.x/packages/hosted-services-integration.html new file mode 100644 index 000000000..186abf081 --- /dev/null +++ b/documentation/quartz-3.x/packages/hosted-services-integration.html @@ -0,0 +1,99 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.Extensions.Hosting (opens new window) +provides integration with hosted services (opens new window).

TIP

Quartz 3.2 or later required for Quartz.Extensions.Hosting. You can use package Quartz.AspNetCore with version 3.1.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Quartz 3.1

Install-Package Quartz.AspNetCore 
+

Quartz 3.2 onwards

Install-Package Quartz.Extensions.Hosting
+

# Using

You can add Quartz configuration by invoking an extension method AddQuartzHostedService on IServiceCollection. +This will add a hosted quartz server into process that will be started and stopped based on applications lifetime.

TIP

See Quartz.Extensions.DependencyInjection documentation to learn more about configuring Quartz scheduler, jobs and triggers.

Example program utilizing hosted services configuration

public class Program
+{
+    public static void Main(string[] args)
+    {
+        Log.Logger = new LoggerConfiguration()
+            .Enrich.FromLogContext()
+            .WriteTo.Console()
+            .CreateLogger();
+        
+        CreateHostBuilder(args).Build().Run();
+    }
+
+    public static IHostBuilder CreateHostBuilder(string[] args) =>
+        Host.CreateDefaultBuilder(args)
+            .UseSerilog()
+            .ConfigureServices((hostContext, services) =>
+            {
+                // see Quartz.Extensions.DependencyInjection documentation about how to configure different configuration aspects
+                services.AddQuartz(q =>
+                {
+                    // your configuration here
+                });
+
+                // Quartz.Extensions.Hosting hosting
+                services.AddQuartzHostedService(options =>
+                {
+                    // when shutting down we want jobs to complete gracefully
+                    options.WaitForJobsToComplete = true;
+                });
+            });
+}
+
+
+ + + diff --git a/documentation/quartz-3.x/packages/json-serialization.html b/documentation/quartz-3.x/packages/json-serialization.html new file mode 100644 index 000000000..cba3c2405 --- /dev/null +++ b/documentation/quartz-3.x/packages/json-serialization.html @@ -0,0 +1,191 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

TIP

JSON is recommended persistent format to store data in database for greenfield projects. +You should also strongly consider setting useProperties to true to restrict key-values to be strings.

Quartz.Serialization.Json (opens new window) provides JSON serialization support for job stores using +Json.NET (opens new window) to handle the actual serialization process.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.Serialization.Json
+

# Configuring

Classic property-based configuration

var properties = new NameValueCollection
+{
+	["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
+	// "json" is alias for "Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json" 
+	["quartz.serializer.type"] = "json"
+};
+ISchedulerFactory schedulerFactory = new StdSchedulerFactory(properties);
+

Configuring using scheduler builder

var config = SchedulerBuilder.Create();
+config.UsePersistentStore(store =>
+{
+    // it's generally recommended to stick with
+    // string property keys and values when serializing
+    store.UseProperties = true;
+    store.UseGenericDatabase(dbProvider, db =>
+        db.ConnectionString = "my connection string"
+    );
+
+    store.UseJsonSerializer();
+});
+ISchedulerFactory schedulerFactory = config.Build();
+

# Migrating from binary serialization

There's now official solution for migration as there can be quirks in every setup, but there's a recipe that can work for you.

  • Configure custom serializer like MigratorSerializer below that can read binary serialization format and writes JSON format
  • Either let system gradually migrate as it's running or create a program which loads and writes back to DB all relevant serialized assets

Example hybrid serializer

public class MigratorSerializer : IObjectSerializer
+{
+    private BinaryObjectSerializer binarySerializer;
+    private JsonObjectSerializer jsonSerializer;
+
+    public MigratorSerializer()
+    {
+        this.binarySerializer = new BinaryObjectSerializer();
+        // you might need custom configuration, see sections about customizing
+        // in documentation
+        this.jsonSerializer = new JsonObjectSerializer();
+    }
+
+    public T DeSerialize<T>(byte[] data) where T : class
+    {
+        try
+        {
+            // Attempt to deserialize data as JSON
+            var result = this.jsonSerializer.DeSerialize<T>(data);
+            return result;
+        }
+        catch (JsonReaderException)
+        {
+            // Presumably, the data was not JSON, we instead use the binary serializer
+            return this.binarySerializer.DeSerialize<T>(data);
+        }
+    }
+
+    public void Initialize()
+    {
+        this.binarySerializer.Initialize();
+        this.jsonSerializer.Initialize();
+    }
+
+    public byte[] Serialize<T>(T obj) where T : class
+    {
+        return this.jsonSerializer.Serialize<T>(obj);
+    }
+}
+

# Customizing JSON.NET

If you need to customize JSON.NET settings, you need to inherit custom implementation and override CreateSerializerSettings.

class CustomJsonSerializer : JsonObjectSerializer
+{
+   protected override JsonSerializerSettings CreateSerializerSettings()
+   {
+       var settings = base.CreateSerializerSettings();
+       settings.Converters.Add(new MyCustomConverter());
+       return settings;
+   }
+} 
+

And then configure it to use

store.UseSerializer<CustomJsonSerializer>();
+// or 
+"quartz.serializer.type" = "MyProject.CustomJsonSerializer, MyProject"
+

# Customizing calendar serialization

If you have implemented a custom calendar, you need to implement a ICalendarSerializer for it. +There's a convenience base class CalendarSerializer that you can use the get strongly-typed experience.

Custom calendar and serializer

[Serializable]
+class CustomCalendar : BaseCalendar
+{
+    public CustomCalendar()
+    {
+    }
+
+    // binary serialization support
+    protected CustomCalendar(SerializationInfo info, StreamingContext context) : base(info, context)
+    {
+        SomeCustomProperty = info?.GetBoolean("SomeCustomProperty") ?? true;
+    }
+
+    public bool SomeCustomProperty { get; set; } = true;
+
+    // binary serialization support
+    public override void GetObjectData(SerializationInfo info, StreamingContext context)
+    {
+        base.GetObjectData(info, context);
+        info?.AddValue("SomeCustomProperty", SomeCustomProperty);
+    }
+}
+
+// JSON serialization support
+class CustomCalendarSerializer : CalendarSerializer<CustomCalendar>
+{
+    protected override CustomCalendar Create(JObject source)
+    {
+        return new CustomCalendar();
+    }
+
+    protected override void SerializeFields(JsonWriter writer, CustomCalendar calendar)
+    {
+        writer.WritePropertyName("SomeCustomProperty");
+        writer.WriteValue(calendar.SomeCustomProperty);
+    }
+
+    protected override void DeserializeFields(CustomCalendar calendar, JObject source)
+    {
+        calendar.SomeCustomProperty = source["SomeCustomProperty"]!.Value<bool>();
+    }
+}
+

Configuring custom calendar serializer

var config = SchedulerBuilder.Create();
+config.UsePersistentStore(store =>
+{
+    store.UseJsonSerializer(json =>
+    {
+        json.AddCalendarSerializer<CustomCalendar>(new CustomCalendarSerializer());
+    });
+});
+
+// or just globally which is what above code calls
+JsonObjectSerializer.AddCalendarSerializer<CustomCalendar>(new CustomCalendarSerializer());
+
+ + + diff --git a/documentation/quartz-3.x/packages/microsoft-di-integration.html b/documentation/quartz-3.x/packages/microsoft-di-integration.html new file mode 100644 index 000000000..bb5c3f94b --- /dev/null +++ b/documentation/quartz-3.x/packages/microsoft-di-integration.html @@ -0,0 +1,255 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.Extensions.DependencyInjection (opens new window) +provides integration with Microsoft Dependency Injection (opens new window).

TIP

Quartz 3.1 or later required.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.Extensions.DependencyInjection
+

# Using

You can add Quartz configuration by invoking an extension method AddQuartz on IServiceCollection. +The configuration building wraps various configuration properties with strongly-typed API. +You can also configure properties using standard .NET Core appsettings.json inside configuration section Quartz.

TIP

Quartz.Extensions.Hosting allows you to have a background service for your application that handles starting and stopping the scheduler.

Example appsettings.json

{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  },
+  "Quartz": {
+    "quartz.scheduler.instanceName": "Quartz ASP.NET Core Sample Scheduler"
+  }
+}
+

# DI aware job factories

Quartz comes with two built-in alternatives for job factory which can be configured via either calling UseMicrosoftDependencyInjectionJobFactory or UseMicrosoftDependencyInjectionScopedJobFactory (deprecated).

TIP

As of Quartz.NET 3.3.2 all jobs produced by the default job factory are scoped jobs, you should no longer use UseMicrosoftDependencyInjectionScopedJobFactory.

# Job instance construction

By default Quartz will try to resolve job's type from container and if there's no explicit registration Quartz will use ActivatorUtilities to construct job and inject it's dependencies +via constructor. Job should have only one public constructor.

# Persistent job stores

The scheduling configuration will be checked against database and updated accordingly every time your application starts and schedule is being evaluated.

WARNING

When using persistent job store, make sure you define job and trigger names for your scheduling so that existence checks work correctly against +the data you already have in your database.

Using API to configure triggers and jobs without explicit job identity configuration will cause jobs and triggers to have different generated name each time configuration is being evaluated.

With persistent job stores it's best practice to always declare at least job and trigger name. Omitting the group for them will produce same default group value for every invocation.

Example Startup.ConfigureServices configuration

public void ConfigureServices(IServiceCollection services)
+{
+    // base configuration from appsettings.json
+    services.Configure<QuartzOptions>(Configuration.GetSection("Quartz"));
+
+    // if you are using persistent job store, you might want to alter some options
+    services.Configure<QuartzOptions>(options =>
+    {
+        options.Scheduling.IgnoreDuplicates = true; // default: false
+        options.Scheduling.OverWriteExistingData = true; // default: true
+    });
+
+    services.AddQuartz(q =>
+    {
+        // handy when part of cluster or you want to otherwise identify multiple schedulers
+        q.SchedulerId = "Scheduler-Core";
+        
+        // we take this from appsettings.json, just show it's possible
+        // q.SchedulerName = "Quartz ASP.NET Core Sample Scheduler";
+        
+        // as of 3.3.2 this also injects scoped services (like EF DbContext) without problems
+        q.UseMicrosoftDependencyInjectionJobFactory();
+
+        // or for scoped service support like EF Core DbContext
+        // q.UseMicrosoftDependencyInjectionScopedJobFactory();
+        
+        // these are the defaults
+        q.UseSimpleTypeLoader();
+        q.UseInMemoryStore();
+        q.UseDefaultThreadPool(tp =>
+        {
+            tp.MaxConcurrency = 10;
+        });
+
+        // quickest way to create a job with single trigger is to use ScheduleJob
+        // (requires version 3.2)
+        q.ScheduleJob<ExampleJob>(trigger => trigger
+            .WithIdentity("Combined Configuration Trigger")
+            .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(7)))
+            .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second))
+            .WithDescription("my awesome trigger configured for a job with single call")
+        );
+
+        // you can also configure individual jobs and triggers with code
+        // this allows you to associated multiple triggers with same job
+        // (if you want to have different job data map per trigger for example)
+        q.AddJob<ExampleJob>(j => j
+            .StoreDurably() // we need to store durably if no trigger is associated
+            .WithDescription("my awesome job")
+        );
+
+        // here's a known job for triggers
+        var jobKey = new JobKey("awesome job", "awesome group");
+        q.AddJob<ExampleJob>(jobKey, j => j
+            .WithDescription("my awesome job")
+        );
+
+        q.AddTrigger(t => t
+            .WithIdentity("Simple Trigger")    
+            .ForJob(jobKey)
+            .StartNow()
+            .WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever())
+            .WithDescription("my awesome simple trigger")
+        );
+
+        q.AddTrigger(t => t
+            .WithIdentity("Cron Trigger")    
+            .ForJob(jobKey)
+            .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(3)))
+            .WithCronSchedule("0/3 * * * * ?")
+            .WithDescription("my awesome cron trigger")
+        );
+
+        // you can add calendars too (requires version 3.2)
+        const string calendarName = "myHolidayCalendar";
+        q.AddCalendar<HolidayCalendar>(
+            name: calendarName,
+            replace: true,
+            updateTriggers: true,
+            x => x.AddExcludedDate(new DateTime(2020, 5, 15))
+        );
+
+        q.AddTrigger(t => t
+            .WithIdentity("Daily Trigger")
+            .ForJob(jobKey)
+            .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(5)))
+            .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second))
+            .WithDescription("my awesome daily time interval trigger")
+            .ModifiedByCalendar(calendarName)
+        );
+        
+        // also add XML configuration and poll it for changes
+        q.UseXmlSchedulingConfiguration(x =>
+        {
+            x.Files = new[] { "~/quartz_jobs.config" };
+            x.ScanInterval = TimeSpan.FromSeconds(2);
+            x.FailOnFileNotFound = true;
+            x.FailOnSchedulingError = true;
+        });
+
+        // convert time zones using converter that can handle Windows/Linux differences
+        q.UseTimeZoneConverter();
+        
+        // auto-interrupt long-running job
+        q.UseJobAutoInterrupt(options =>
+        {
+            // this is the default
+            options.DefaultMaxRunTime = TimeSpan.FromMinutes(5);
+        });
+        q.ScheduleJob<SlowJob>(
+            triggerConfigurator => triggerConfigurator
+                .WithIdentity("slowJobTrigger")
+                .StartNow()
+                .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever()),
+            jobConfigurator => jobConfigurator
+                .WithIdentity("slowJob")
+                .UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyAutoInterruptable, true)
+                // allow only five seconds for this job, overriding default configuration
+                .UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyMaxRunTime, TimeSpan.FromSeconds(5).TotalMilliseconds.ToString(CultureInfo.InvariantCulture)));
+
+        // add some listeners
+        q.AddSchedulerListener<SampleSchedulerListener>();
+        q.AddJobListener<SampleJobListener>(GroupMatcher<JobKey>.GroupEquals(jobKey.Group));
+        q.AddTriggerListener<SampleTriggerListener>();
+
+        // example of persistent job store using JSON serializer as an example
+        /*
+        q.UsePersistentStore(s =>
+        {
+            s.UseProperties = true;
+            s.RetryInterval = TimeSpan.FromSeconds(15);
+            s.UseSqlServer(sqlServer =>
+            {
+                sqlServer.ConnectionString = "some connection string";
+                // this is the default
+                sqlServer.TablePrefix = "QRTZ_";
+            });
+            s.UseJsonSerializer();
+            s.UseClustering(c =>
+            {
+                c.CheckinMisfireThreshold = TimeSpan.FromSeconds(20);
+                c.CheckinInterval = TimeSpan.FromSeconds(10);
+            });
+        });
+        */
+    });
+	
+	// we can use options pattern to support hooking your own configuration
+	// because we don't use service registration api, 
+	// we need to manually ensure the job is present in DI
+	services.AddTransient<ExampleJob>();
+				
+	services.Configure<SampleOptions>(Configuration.GetSection("Sample"));
+	services.AddOptions<QuartzOptions>()
+		.Configure<IOptions<SampleOptions>>((options, dep) =>
+		{
+			if (!string.IsNullOrWhiteSpace(dep.Value.CronSchedule))
+			{
+				var jobKey = new JobKey("options-custom-job", "custom");
+				options.AddJob<ExampleJob>(j => j.WithIdentity(jobKey));
+				options.AddTrigger(trigger => trigger
+					.WithIdentity("options-custom-trigger", "custom")
+					.ForJob(jobKey)
+					.WithCronSchedule(dep.Value.CronSchedule));
+			}
+		});	
+		
+    // Quartz.Extensions.Hosting allows you to fire background service that handles scheduler lifecycle
+    services.AddQuartzHostedService(options =>
+    {
+        // when shutting down we want jobs to complete gracefully
+        options.WaitForJobsToComplete = true;
+    });
+}
+
+ + + diff --git a/documentation/quartz-3.x/packages/opentelemetry-integration.html b/documentation/quartz-3.x/packages/opentelemetry-integration.html new file mode 100644 index 000000000..e84b5849e --- /dev/null +++ b/documentation/quartz-3.x/packages/opentelemetry-integration.html @@ -0,0 +1,94 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.OpenTelemetry.Instrumentation (opens new window) +provides integration with OpenTelemetry (opens new window).

TIP

Quartz 3.1 or later required.

WARNING

The integration library can still live a bit and thus integration API can have breaking changes and change behavior.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.OpenTelemetry.Instrumentation
+

It also makes sense to install package for exporter to actually get the results somewhere.

# Using

You can add Quartz configuration by invoking an extension method AddQuartzInstrumentation on TracerProviderBuilder.

In the next example we will integrate with Jaeger (opens new window). We expect that you have also installed dependencies:

You can run local Jaeger via docker using:

$ docker run -d --name jaeger \
+  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
+  -p 5775:5775/udp \
+  -p 6831:6831/udp \
+  -p 6832:6832/udp \
+  -p 5778:5778 \
+  -p 16686:16686 \
+  -p 14268:14268 \
+  -p 14250:14250 \
+  -p 9411:9411 \
+  jaegertracing/all-in-one:1.18
+

Example Startup.ConfigureServices configuration

public void ConfigureServices(IServiceCollection services)
+{
+    // make sure you configure logging and open telemetry before quartz services
+
+    services.AddOpenTelemetry(builder =>
+    {
+        builder
+            .AddQuartzInstrumentation()
+            .UseJaegerExporter(o =>
+            {
+                o.ServiceName = "My Software Name";
+
+                // these are the defaults
+                o.AgentHost = "localhost";
+                o.AgentPort = 6831;
+            });
+    });
+}
+
+ + + diff --git a/documentation/quartz-3.x/packages/opentracing-integration.html b/documentation/quartz-3.x/packages/opentracing-integration.html new file mode 100644 index 000000000..9223b2cdc --- /dev/null +++ b/documentation/quartz-3.x/packages/opentracing-integration.html @@ -0,0 +1,77 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.OpenTracing (opens new window) +provides integration with OpenTracing (opens new window). You may also consider +Quartz.OpenTelemetry.Instrumentation package which will supercede OpenTracing and OpenCensus +when OpenTelemetry project reaches maturity.

TIP

Quartz 3.2.3 or later required.

WARNING

The integration library can still live a bit and thus integration API can have breaking changes and change behavior.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.OpenTracing
+

# Using

You can add Quartz configuration by invoking an extension method AddQuartzOpenTracing on IServiceCollection.

Example Startup.ConfigureServices configuration

public void ConfigureServices(IServiceCollection services)
+{
+    // make sure you configure logging and OpenTracing before quartz services
+    services.AddQuartzOpenTracing(options =>
+    {
+        // these are the defaults
+        options.ComponentName = "Quartz";
+        options.IncludeExceptionDetails = false;
+    });
+}
+
+ + + diff --git a/documentation/quartz-3.x/packages/quartz-jobs.html b/documentation/quartz-3.x/packages/quartz-jobs.html new file mode 100644 index 000000000..bfd12b36f --- /dev/null +++ b/documentation/quartz-3.x/packages/quartz-jobs.html @@ -0,0 +1,71 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.Jobs (opens new window) provides some useful ready-made jobs for your convenience.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.Jobs
+

# Features

# DirectoryScanJob

Inspects a directory and compares whether any files' "last modified dates" have changed since the last time it was inspected. +If one or more files have been updated (or created), the job invokes a "call-back" method on an IDirectoryScanListenerthat can be found in the SchedulerContext.

# FileScanJob

Inspects a file and compares whether its "last modified dates" have changed since the last time it was inspected. +If one or more files have been updated (or created), the job invokes a "call-back" method on an IFileScanListenerthat can be found in the SchedulerContext.

# NativeJob

Built in job for executing native executables in a separate process.

Example*

var job = new JobDetail("dumbJob", null, typeof(Quartz.Jobs.NativeJob));
+job.JobDataMap.Put(Quartz.Jobs.NativeJob.PropertyCommand, "echo \"hi\" >> foobar.txt");
+var trigger = TriggerUtils.MakeSecondlyTrigger(5);
+trigger.Name = "dumbTrigger";
+await scheduler.ScheduleJob(job, trigger);
+

If PropertyWaitForProcess is true, then the integer exit value of the process will be saved as the job execution result in the JobExecutionContext.

# SendMailJob

A Job which sends an e-mail with the configured content to the configured recipient.

+ + + diff --git a/documentation/quartz-3.x/packages/quartz-plugins.html b/documentation/quartz-3.x/packages/quartz-plugins.html new file mode 100644 index 000000000..2f9309a9d --- /dev/null +++ b/documentation/quartz-3.x/packages/quartz-plugins.html @@ -0,0 +1,71 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.Plugins (opens new window) provides some useful ready-mady plugins for your convenience.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.Plugins
+

# Configuration

Plugins are configured by using either DI configuration extensions or adding required configuration keys.

Configuration key in in format quartz.plgin.{name-to-refer-with}.{property}.

See configuration reference on how to configure each plugin

# Features

# LoggingJobHistoryPlugin

Logs a history of all job executions (and execution vetoes) and writes the entries to configured logging infrastructure.

# ShutdownHookPlugin

This plugin catches the event of the VM terminating (such as upon a CRTL-C) and tells the scheduler to Shutdown.

# XMLSchedulingDataProcessorPlugin

This plugin loads XML file(s) to add jobs and schedule them with triggers as the scheduler is initialized, and can optionally periodically scan thefile for changes.

WARNING

The periodically scanning of files for changes is not currently supported in a clustered environment.

# JobInterruptMonitorPlugin

This plugin catches the event of job running for a long time (more than the configured max time) and tells the scheduler to "try" interrupting it if enabled.

TIP

Quartz 3.3 or later required.

Each job configuration needs to have JobInterruptMonitorPlugin.JobDataMapKeyAutoInterruptable key's value set to true in order for plugin to monitor the execution timeout. +Jobs can also define custom timeout value instead of global default by using key JobInterruptMonitorPlugin.JobDataMapKeyMaxRunTime.

var job = JobBuilder.Create<SlowJob>()
+    .WithIdentity("slowJob")
+    .UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyAutoInterruptable, true)
+    // allow only five seconds for this job, overriding default configuration
+    .UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyMaxRunTime, TimeSpan.FromSeconds(5).TotalMilliseconds.ToString(CultureInfo.InvariantCulture))
+    .Build();
+
+ + + diff --git a/documentation/quartz-3.x/packages/timezoneconverter-integration.html b/documentation/quartz-3.x/packages/timezoneconverter-integration.html new file mode 100644 index 000000000..fb238204c --- /dev/null +++ b/documentation/quartz-3.x/packages/timezoneconverter-integration.html @@ -0,0 +1,74 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz.Plugins.TimeZoneConverter (opens new window) +provides integration with TimeZoneConverter (opens new window) which helps to bridge between +*nix and Windows differences.

# Installation

You need to add NuGet package reference to your project which uses Quartz.

Install-Package Quartz.Plugins.TimeZoneConverter
+

# Using

Classic property-based configuration

var properties = new NameValueCollection
+{
+	["quartz.plugin.timeZoneConverter.type"] = "Quartz.Plugin.TimeZoneConverter.TimeZoneConverterPlugin, Quartz.Plugins.TimeZoneConverter"
+};
+ISchedulerFactory schedulerFactory = new StdSchedulerFactory(properties);
+

Configuring using scheduler builder

var config = SchedulerBuilder.Create()
+    .UseTimeZoneConverter();
+ISchedulerFactory schedulerFactory = config.Build();
+
+ + + diff --git a/documentation/quartz-3.x/quick-start.html b/documentation/quartz-3.x/quick-start.html new file mode 100644 index 000000000..a02882f74 --- /dev/null +++ b/documentation/quartz-3.x/quick-start.html @@ -0,0 +1,280 @@ + + + + + + Quartz.NET Quick Start Guide | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Welcome to the Quick Start Guide for Quartz.NET. As you read this guide, expect to see details of:

  • Downloading Quartz.NET
  • Installing Quartz.NET
  • Configuring Quartz to your own particular needs
  • Starting a sample application

# Download and Install

You can either download the zip file or use the NuGet package. +NuGet package contains only the binaries needed to run Quartz.NET, zip file comes with source code, samples and Quartz.NET server sample application.

# NuGet Package

Couldn't get any simpler than this. Just fire up Visual Studio (with NuGet installed) and add reference to package Quartz from package manager extension:

  • Right-click on your project's References and choose Manage NuGet Packages...
  • Choose Online category from the left
  • Enter Quartz to the top right search and hit enter
  • Choose Quartz.NET from search results and hit install
  • Done!

or from NuGet Command-Line:

Install-Package Quartz
+

If you want to add JSON Serialization, just add the Quartz.Serialization.Json package the same way.

# Zip Archive

Short version: Once you've downloaded Quartz.NET, unzip it somewhere, grab the Quartz.dll from bin directory and start to use it.

Quartz core library does not have any hard binary dependencies. You can opt-in to more dependencies when you choose to use JSON serialization package, which requires JSON.NET. +You need to have at least Quartz.dll beside your app binaries to successfully run Quartz.NET. So just add it as a references to your Visual Studio project that uses them. +You can find these dlls from extracted archive from path bin\your-target-framework-version\release\Quartz.

# Configuration

This is the big bit! Quartz.NET is a very configurable library. There are two main ways (which are not mutually exclusive) to supply Quartz.NET configuration information:

# Fluent Scheduler Builder API

You can configure scheduler using C# fluent API, or via providing NameValueCollection parameter to scheduler factory +which contains configuration keys and values.

// you can have base properties
+var properties = new NameValueCollection();
+
+// and override values via builder
+IScheduler scheduler = await SchedulerBuilder.Create(properties)
+    // default max concurrency is 10
+    .UseDefaultThreadPool(x => x.MaxConcurrency = 5)
+    // this is the default 
+    // .WithMisfireThreshold(TimeSpan.FromSeconds(60))
+    .UsePersistentStore(x =>
+    {
+        // force job data map values to be considered as strings
+        // prevents nasty surprises if object is accidentally serialized and then 
+        // serialization format breaks, defaults to false
+        x.UseProperties = true;
+        x.UseClustering();
+        // there are other SQL providers supported too 
+        x.UseSqlServer("my connection string");
+        // this requires Quartz.Serialization.Json NuGet package
+        x.UseJsonSerializer();
+    })
+    // job initialization plugin handles our xml reading, without it defaults are used
+    // requires Quartz.Plugins NuGet package
+    .UseXmlSchedulingConfiguration(x =>
+    {
+        x.Files = new[] { "~/quartz_jobs.xml" };
+        // this is the default
+        x.FailOnFileNotFound = true;
+        // this is not the default
+        x.FailOnSchedulingError = true;
+    })
+    .BuildScheduler();
+
+await scheduler.Start();
+

# Configuration files

Following files are searched for known configuration properties:

  • YourApplication.exe.config configuration file using quartz-element (full .NET framework only)
  • appsettings.json (.NET Core/NET5 onwards)
  • quartz.config file in your application's root directory (works both with .NET Core and full .NET Framework)

Full documentation of available properties is available in the Quartz Configuration Reference.

To get up and running quickly, a basic quartz.config looks something like this:

quartz.scheduler.instanceName = MyScheduler
+quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
+quartz.threadPool.maxConcurrency = 3
+

Remember to set the Copy to Output Directory on Visual Studio's file property pages to have value Copy always. Otherwise the config will not be seen if it's not in build directory.

The scheduler created by this configuration has the following characteristics:

  • quartz.scheduler.instanceName - This scheduler's name will be "MyScheduler".

  • quartz.threadPool.maxConcurrency - Maximum of 3 jobs can be run simultaneously (default is 10).

  • quartz.jobStore.type - All of Quartz's data, such as details of jobs and triggers, is held in memory (rather than in a database).

  • Even if you have a database and want to use it with Quartz, I suggest you get Quartz working with the RamJobStore before you open up a whole new dimension by working with a database.

TIP

Actually you don't need to define these properties if you don't want to, Quartz.NET comes with sane defaults

# Starting a Sample Application

Now you've downloaded and installed Quartz, it's time to get a sample application up and running. The following code obtains an instance of the scheduler, starts it, then shuts it down:

Program.cs

using System;
+using System.Threading.Tasks;
+
+using Quartz;
+using Quartz.Impl;
+
+namespace QuartzSampleApp
+{
+    public class Program
+    {
+        private static async Task Main(string[] args)
+        {
+            // Grab the Scheduler instance from the Factory
+            StdSchedulerFactory factory = new StdSchedulerFactory();
+            IScheduler scheduler = await factory.GetScheduler();
+
+            // and start it off
+            await scheduler.Start();
+
+            // some sleep to show what's happening
+            await Task.Delay(TimeSpan.FromSeconds(10));
+
+            // and last shut down the scheduler when you are ready to close your program
+            await scheduler.Shutdown();
+        }
+    }
+}
+

As of Quartz 3.0 your application will terminate when there's no code left to execute after scheduler.Shutdown(), because there won't be any active threads. You should manually block exiting of application if you want scheduler to keep running also after the Task.Delay and Shutdown has been processed.

Now running the program will not show anything. When 10 seconds have passed the program will just terminate. Lets add some logging to console.

# Adding logging

LibLog (opens new window) can be configured to use different logging frameworks under the hood; namely Log4Net, NLog and Serilog.

When LibLog does not detect any other logging framework to be present, it will be silent. We can configure a custom logger provider that just logs to console show the output +if you don't have logging framework setup ready yet.

LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
+
+private class ConsoleLogProvider : ILogProvider
+{
+    public Logger GetLogger(string name)
+    {
+        return (level, func, exception, parameters) =>
+        {
+            if (level >= LogLevel.Info && func != null)
+            {
+                Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
+            }
+            return true;
+        };
+    }
+
+    public IDisposable OpenNestedContext(string message)
+    {
+        throw new NotImplementedException();
+    }
+
+    public IDisposable OpenMappedContext(string key, object value, bool destructure = false)
+    {
+        throw new NotImplementedException();
+    }
+}
+

# Trying out the application and adding jobs

Now we should get a lot more information when we start the application.

[12.51.10] [Info] Quartz.NET properties loaded from configuration file 'C:\QuartzSampleApp\quartz.config'
+[12.51.10] [Info] Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
+[12.51.10] [Info] Quartz Scheduler created
+[12.51.10] [Info] RAMJobStore initialized.
+[12.51.10] [Info] Scheduler meta-data: Quartz Scheduler (v3.0.0.0) 'MyScheduler' with instanceId 'NON_CLUSTERED'
+  Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
+  NOT STARTED.
+  Currently in standby mode.
+  Number of jobs executed: 0
+  Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 3 threads.
+  Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.
+
+[12.51.10] [Info] Quartz scheduler 'MyScheduler' initialized
+[12.51.10] [Info] Quartz scheduler version: 3.0.0.0
+[12.51.10] [Info] Scheduler MyScheduler_$_NON_CLUSTERED started.
+

We need a simple test job to test the functionality, lets create HelloJob that outputs greetings to console.

public class HelloJob : IJob
+{
+	public async Task Execute(IJobExecutionContext context)
+	{
+		await Console.Out.WriteLineAsync("Greetings from HelloJob!");
+	}
+}
+

To do something interesting, you need code just after Start() method, before the Task.Delay.

// define the job and tie it to our HelloJob class
+IJobDetail job = JobBuilder.Create<HelloJob>()
+	.WithIdentity("job1", "group1")
+	.Build();
+
+// Trigger the job to run now, and then repeat every 10 seconds
+ITrigger trigger = TriggerBuilder.Create()
+	.WithIdentity("trigger1", "group1")
+	.StartNow()
+	.WithSimpleSchedule(x => x
+		.WithIntervalInSeconds(10)
+		.RepeatForever())
+	.Build();
+
+// Tell quartz to schedule the job using our trigger
+await scheduler.ScheduleJob(job, trigger);
+
+// You could also schedule multiple triggers for the same job with
+// await scheduler.ScheduleJob(job, new List<ITrigger>() { trigger1, trigger2 }, replace: true);
+

The complete console application will now look like this

using System;
+using System.Threading.Tasks;
+
+using Quartz;
+using Quartz.Impl;
+using Quartz.Logging;
+
+namespace QuartzSampleApp
+{
+    public class Program
+    {
+        private static async Task Main(string[] args)
+        {
+            LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
+
+            // Grab the Scheduler instance from the Factory
+            StdSchedulerFactory factory = new StdSchedulerFactory();
+            IScheduler scheduler = await factory.GetScheduler();
+
+            // and start it off
+            await scheduler.Start();
+
+            // define the job and tie it to our HelloJob class
+            IJobDetail job = JobBuilder.Create<HelloJob>()
+                .WithIdentity("job1", "group1")
+                .Build();
+
+            // Trigger the job to run now, and then repeat every 10 seconds
+            ITrigger trigger = TriggerBuilder.Create()
+                .WithIdentity("trigger1", "group1")
+                .StartNow()
+                .WithSimpleSchedule(x => x
+                    .WithIntervalInSeconds(10)
+                    .RepeatForever())
+                .Build();
+
+            // Tell quartz to schedule the job using our trigger
+            await scheduler.ScheduleJob(job, trigger);
+
+            // some sleep to show what's happening
+            await Task.Delay(TimeSpan.FromSeconds(60));
+
+            // and last shut down the scheduler when you are ready to close your program
+            await scheduler.Shutdown();
+
+            Console.WriteLine("Press any key to close the application");
+            Console.ReadKey();
+        }
+
+        // simple log provider to get something to the console
+        private class ConsoleLogProvider : ILogProvider
+        {
+            public Logger GetLogger(string name)
+            {
+                return (level, func, exception, parameters) =>
+                {
+                    if (level >= LogLevel.Info && func != null)
+                    {
+                        Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
+                    }
+                    return true;
+                };
+            }
+
+            public IDisposable OpenNestedContext(string message)
+            {
+                throw new NotImplementedException();
+            }
+
+            public IDisposable OpenMappedContext(string key, object value, bool destructure = false)
+            {
+                throw new NotImplementedException();
+            }
+        }
+    }
+
+    public class HelloJob : IJob
+    {
+        public async Task Execute(IJobExecutionContext context)
+        {
+            await Console.Out.WriteLineAsync("Greetings from HelloJob!");
+        }
+    }
+}
+

Now go have some fun exploring Quartz.NET! You can continue by reading the tutorial.

+ + + diff --git a/documentation/quartz-3.x/tutorial/advanced-enterprise-features.html b/documentation/quartz-3.x/tutorial/advanced-enterprise-features.html new file mode 100644 index 000000000..9c5586691 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/advanced-enterprise-features.html @@ -0,0 +1,71 @@ + + + + + + Advanced (Enterprise) Features | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Clustering

Clustering currently only works with the AdoJobstore (JobStoreTX). +Features include load-balancing and job fail-over (if the JobDetail's "request recovery" flag is set to true).

Enable clustering by setting the quartz.jobStore.clustered property to "true". +Each instance in the cluster should use the same copy of the quartz properties. +Exceptions of this would be to use properties that are identical, with the following allowable exceptions: +Different thread pool size, and different value for the quartz.scheduler.instanceId property. +Each node in the cluster MUST have a unique instanceId, which is easily done (without needing different properties files) by placing AUTO as the value of this property.

WARNING

Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly (the clocks must be within a second of each other). +See https://www.nist.gov/pml/time-and-frequency-division/services/internet-time-service-its (opens new window) if you are unfamiliar with how to do this.

WARNING

Never start (scheduler.Start()) a non-clustered instance against the same set of database tables that any other instance is running (Start()ed) against. +You may get serious data corruption, and will definitely experience erratic behavior.

WARNING

Monitor and ensure that your nodes have enough CPU resources to complete jobs. +When some nodes are in 100% CPU, they may be unable to update the job store and other nodes can consider these jobs lost and recover them by re-running.

+ + + diff --git a/documentation/quartz-3.x/tutorial/configuration-resource-usage-and-scheduler-factory.html b/documentation/quartz-3.x/tutorial/configuration-resource-usage-and-scheduler-factory.html new file mode 100644 index 000000000..1c38393ff --- /dev/null +++ b/documentation/quartz-3.x/tutorial/configuration-resource-usage-and-scheduler-factory.html @@ -0,0 +1,90 @@ + + + + + + Configuration, Resource Usage and SchedulerFactory | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Quartz is architected in modular way, and therefore to get it running, several components need to be "snapped" together. +Fortunately, some helpers exist for making this happen.

The major components that need to be configured before Quartz can do its work are:

  • ThreadPool
  • JobStore
  • DataSources (if necessary)
  • The Scheduler itself

Thread pooling has changed a lot since the Task-based jobs were introduced. +Now the default implementation, DefaultThreadPool uses CLR's managed thread pool (opens new window) to execute jobs as tasks. +You can configure the pool that have max concurrency, which effectively limits how many concurrent tasks can be scheduled to the CLR's thread pool. +See configuration reference for more details on how to configure the thread pool implementation.

JobStores and DataSources were discussed in Lesson 9 of this tutorial. Worth noting here, is the fact that all JobStores +implement the IJobStore interface - and that if one of the bundled JobStores does not fit your needs, then you can make your own.

Finally, you need to create your Scheduler instance. The Scheduler itself needs to be given a name and handed +instances of a JobStore and ThreadPool.

# StdSchedulerFactory

StdSchedulerFactory is an implementation of the ISchedulerFactory interface. +It uses a set of properties (NameValueCollection) to create and initialize a Quartz Scheduler. +The properties are generally stored in and loaded from a file, but can also be created by your program and handed directly to the factory. +Simply calling GetScheduler() on the factory will produce the scheduler, initialize it (and its ThreadPool, JobStore and DataSources), +and return a handle to its public interface.

You can find complete documentation in the "Configuration Reference" section of the Quartz documentation.

# DirectSchedulerFactory

DirectSchedulerFactory is another ISchedulerFactory implementation. It is useful to those wishing to create their Scheduler +instance in a more programmatic way. Its use is generally discouraged for the following reasons:

  • It requires the user to have a greater understanding of what they're doing, and
  • it does not allow for declarative configuration - or in other words, you end up hard-coding all of the scheduler's settings.

# Logging

TIP

As of Quartz.NET 3.1, you can configure Microsoft.Extensions.Logging.Abstractions (opens new window) to be used instead of LibLog.

# LibLog

Quartz.NET uses LibLog library for all of its logging needs. +Quartz does not produce much logging information - generally just some information during initialization, and +then only messages about serious problems while Jobs are executing. In order to "tune" the logging settings +(such as the amount of output, and where the output goes), you need to actually configure your logging framework of choice as LibLog mostly delegates the work to +more full-fledged logging framework like log4net, serilog etc.

Please see LibLog Wiki for more information.

# Microsoft.Extensions.Logging.Abstractions

You can configure Microsoft.Extensions.Logging.Abstractions either manually or using services found in Quartz.Extensions.DependencyInjection (opens new window).

# Manual configuration

// obtain your logger factory, for example from IServiceProvider
+ILoggerFactory loggerFactory = ...;
+
+// Quartz 3.1
+Quartz.LogContext.SetCurrentLogProvider(loggerFactory);
+
+// Quartz 3.2 onwards
+Quartz.Logging.LogContext.SetCurrentLogProvider(loggerFactory);
+

# Configuration using Microsoft DI integration.

services.AddQuartz(q =>
+{
+    // this automatically registers the Microsoft Logging
+});
+
+ + + diff --git a/documentation/quartz-3.x/tutorial/crontrigger.html b/documentation/quartz-3.x/tutorial/crontrigger.html new file mode 100644 index 000000000..810728f2f --- /dev/null +++ b/documentation/quartz-3.x/tutorial/crontrigger.html @@ -0,0 +1,84 @@ + + + + + + CronTrigger Tutorial | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Introduction

cron is a UNIX tool that has been around for a long time, so its scheduling capabilities are powerful and proven. +The CronTrigger class is based on the scheduling capabilities of cron.

CronTrigger uses "cron expressions", which are able to create firing schedules such as: "At 8:00am every Monday through Friday" or "At 1:30am every last Friday of the month".

Cron expressions are powerful, but can be pretty confusing. This tutorial aims to take some of the mystery out of creating a cron expression, +giving users a resource which they can visit before having to ask in a forum or mailing list.

# Format

A cron expression is a string comprised of 6 or 7 fields separated by white space. +Fields can contain any of the allowed values, along with various combinations of the allowed special characters for that field. The fields are as follows:

Field Name Mandatory Allowed Values Allowed Special Characters
Seconds YES 0-59 , - * /
Minutes YES 0-59 , - * /
Hours YES 0-23 , - * /
Day of month YES 1-31 , - * ? / L W
Month YES 1-12 or JAN-DEC , - * /
Day of week YES 1-7 or SUN-SAT , - * ? / L #
Year NO empty, 1970-2099 , - * /

So cron expressions can be as simple as this: * * * * ? *

or more complex, like this: 0/5 14,18,3-39,52 * ? JAN,MAR,SEP MON-FRI 2002-2010

# Special characters

  • * ("all values") - used to select all values within a field. For example, * in the minute field means "every minute".
  • ? ("no specific value") - useful when you need to specify something in one of the two fields in which the character is allowed, but not the other. +For example, if I want my trigger to fire on a particular day of the month (say, the 10th), but don't care what day of the week that happens to be, +I would put 10 in the day-of-month field, and ? in the day-of-week field. See the examples below for clarification.
  • - - used to specify ranges. For example, 10-12 in the hour field means "the hours 10, 11 and 12".
  • , - used to specify additional values. For example, MON,WED,FRI in the day-of-week field means "the days Monday, Wednesday, and Friday".
  • / - used to specify increments. For example, 0/15 in the seconds field means "the seconds 0, 15, 30, and 45". +And 5/15 in the seconds field means "the seconds 5, 20, 35, and 50". +You can also specify / after the "character - in this case" is equivalent to having '0' before the '/'. +1/3 in the day-of-month field means "fire every 3 days starting on the first day of the month".
  • L ("last") - has different meaning in each of the two fields in which it is allowed. +For example, the value L in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. +If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - +for example 6L means "the last friday of the month". You can also specify an offset from the last day of the month, such as L-3 which +would mean the third-to-last day of the calendar month. When using the L option, it is important not to specify lists, or ranges of values, +as you'll get confusing/unexpected results.
  • W ("weekday") - used to specify the weekday (Monday-Friday) nearest the given day. +As an example, if you were to specify 15W as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month". +So if the 15th is a Saturday, the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the 16th. If the 15th is a Tuesday, +then it will fire on Tuesday the 15th. However if you specify 1W as the value for day-of-month, and the 1st is a Saturday, the trigger will fire on Monday the 3rd, +as it will not 'jump' over the boundary of a month's days. The W character can only be specified when the day-of-month is a single day, not a range or list of days.

TIP

The L and W characters can also be combined in the day-of-month field to yield LW, which translates to *"last weekday of the month".

  • # - used to specify "the nth" XXX day of the month. For example, the value of 6#3 in the day-of-week field means +"the third Friday of the month" (day 6 = Friday and "#3" = the 3rd one in the month). +Other examples: 2#1 = the first Monday of the month and 4#5 = the fifth Wednesday of the month. +Note that if you specify #5 and there is not 5 of the given day-of-week in the month, then no firing will occur that month.

TIP

The legal characters and the names of months and days of the week are not case sensitive. MON is the same as mon.

# Examples

Here are some full examples:

Expression Meaning
0 0 12 * * ? Fire at 12pm (noon) every day
0 15 10 ? * * Fire at 10:15am every day
0 15 10 * * ? Fire at 10:15am every day
0 15 10 * * ? * Fire at 10:15am every day
0 15 10 * * ? 2005 Fire at 10:15am every day during the year 2005
0 * 14 * * ? Fire every minute starting at 2pm and ending at 2:59pm, every day
0 0/5 14 * * ? Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day
0 0/5 14,18 * * ? Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day
0 0-5 14 * * ? Fire every minute starting at 2pm and ending at 2:05pm, every day
0 10,44 14 ? 3 WED Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.
0 15 10 ? * MON-FRI Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday
0 15 10 15 * ? Fire at 10:15am on the 15th day of every month
0 15 10 L * ? Fire at 10:15am on the last day of every month
0 15 10 L-2 * ? Fire at 10:15am on the 2nd-to-last last day of every month
0 15 10 ? * 6L Fire at 10:15am on the last Friday of every month
0 15 10 ? * 6L Fire at 10:15am on the last Friday of every month
0 15 10 ? * 6L 2002-2005 Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005
0 15 10 ? * 6#3 Fire at 10:15am on the third Friday of every month
0 0 12 1/5 * ? Fire at 12pm (noon) every 5 days every month, starting on the first day of the month.
0 11 11 11 11 ? Fire every November 11th at 11:11am.

TIP

Pay attention to the effects of '?' and '*' in the day-of-week and day-of-month fields!

# Notes

WARNING

Support for specifying both a day-of-week and a day-of-month value is not complete (you must currently use the '?' character in one of these fields).

WARNING

Be careful when setting fire times between the hours of the morning when "daylight savings" changes occur in your locale (for US locales, this would typically be the hour before and after 2:00 AM - because the time shift can cause a skip or a repeat depending on whether the time moves back or jumps forward. You may find this wikipedia entry helpful in determining the specifics to your locale: +https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world (opens new window)

+ + + diff --git a/documentation/quartz-3.x/tutorial/crontriggers.html b/documentation/quartz-3.x/tutorial/crontriggers.html new file mode 100644 index 000000000..4aeac6b4a --- /dev/null +++ b/documentation/quartz-3.x/tutorial/crontriggers.html @@ -0,0 +1,128 @@ + + + + + + CronTrigger | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

CronTriggers are often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions, +rather than on the exactly specified intervals of SimpleTrigger.

With CronTrigger, you can specify firing-schedules such as "every Friday at noon", or "every weekday and 9:30 am", +or even "every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday".

Even so, like SimpleTrigger, CronTrigger has a startTime which specifies when the schedule is in force, and an (optional) +endTime that specifies when the schedule should be discontinued.

# Cron Expressions

Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up +of seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:

    1. Seconds
    1. Minutes
    1. Hours
    1. Day-of-Month
    1. Month
    1. Day-of-Week
    1. Year (optional field)

An example of a complete cron-expression is the string 0 0 12 ? * WED - which means "every Wednesday at 12:00 pm".

Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED") +example could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".

Wild-cards (the * character) can be used to say "every" possible value of this field. Therefore the * character in the +"Month" field of the previous example simply means "every month". A * in the Day-Of-Week field would obviously mean "every day of the week".

All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers +0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful +about how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings +JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday) +or by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.

The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes, +starting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour, +starting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.

The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify "no specific value". +This is useful when you need to specify something in one of the two fields, but not the other. +See the examples below (and CronTrigger API documentation) for clarification.

The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last", +but it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means +"the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, +it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - +for example "6L" or "FRIL" both mean "the last friday of the month". When using the 'L' option, it is important not to specify lists, +or ranges of values, as you'll get confusing results.

The 'W' is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month".

The '#' is used to specify "the nth" XXX weekday of the month. For example, the value of "6#3" or "FRI#3" in the day-of-week field means "the third Friday of the month".

# Example Cron Expressions

Here are a few more examples of expressions and their meanings - you can find even more in the API documentation for CronTrigger

CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes

"0 0/5 * * * ?"
+

CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).

"10 0/5 * * * ?"
+

CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.

"0 30 10-13 ? * WED,FRI"
+

CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month. +Note that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30

"0 0/30 8-9 5,20 * ?"
+

Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am, +and every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.

# Building CronTriggers

CronTrigger instances are built using TriggerBuilder (for the trigger's main properties) and WithCronSchedule +extension method (for the CronTrigger-specific properties).

You can also use CronScheduleBuilder's static methods to create schedules.

Build a trigger that will fire every other minute, between 8am and 5pm, every day:

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 0/2 8-17 * * ?")
+    .ForJob("myJob", "group1")
+    .Build();
+

Build a trigger that will fire daily at 10:42 am:

// we use CronScheduleBuilder's static helper methods here
+ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 42))
+    .ForJob(myJobKey)
+    .Build();
+

or -

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 42 10 * * ?")
+    .ForJob("myJob", "group1")
+    .Build();
+

Build a trigger that will fire on Wednesdays at 10:42 am, in a TimeZone other than the system's default:

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithSchedule(CronScheduleBuilder
+        .WeeklyOnDayAndHourAndMinute(DayOfWeek.Wednesday, 10, 42)
+        .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
+    .ForJob(myJobKey)
+    .Build();
+

or -

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 42 10 ? * WED", x => x
+        .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
+    .ForJob(myJobKey)
+    .Build();
+

# CronTrigger Misfire Instructions

The following instructions can be used to inform Quartz what it should do when a misfire occurs for CronTrigger. +(Misfire situations were introduced in the More About Triggers section of this tutorial). These instructions are defined in as +constants (and API documentation has description for their behavior). The instructions include:

  • MisfireInstruction.IgnoreMisfirePolicy
  • MisfireInstruction.CronTrigger.DoNothing
  • MisfireInstruction.CronTrigger.FireOnceNow

All triggers have the MisfireInstrution.SmartPolicy instruction available for use, and this instruction is also the default for all trigger types. +The 'smart policy' instruction is interpreted by CronTrigger as MisfireInstruction.CronTrigger.FireOnceNow. The API documentation for the +CronTrigger.UpdateAfterMisfire() method explains the exact details of this behavior.

When building CronTriggers, you specify the misfire instruction as part of the cron schedule (via WithCronSchedule extension method):

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .WithCronSchedule("0 0/2 8-17 * * ?", x => x
+        .WithMisfireHandlingInstructionFireAndProceed())
+    .ForJob("myJob", "group1")
+    .Build();
+
+ + + diff --git a/documentation/quartz-3.x/tutorial/index.html b/documentation/quartz-3.x/tutorial/index.html new file mode 100644 index 000000000..162ac3874 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/index.html @@ -0,0 +1,59 @@ + + + + + + Quartz.NET 3.x Tutorial | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/documentation/quartz-3.x/tutorial/job-stores.html b/documentation/quartz-3.x/tutorial/job-stores.html new file mode 100644 index 000000000..bf2102791 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/job-stores.html @@ -0,0 +1,114 @@ + + + + + + Job Stores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

JobStore's are responsible for keeping track of all the "work data" that you give to the scheduler: +jobs, triggers, calendars, etc. Selecting the appropriate IJobStore implementation for your Quartz scheduler instance is an important step. +Luckily, the choice should be a very easy one once you understand the differences between them. +You declare which JobStore your scheduler should use (and it's configuration settings) in the properties file (or object) that +you provide to the SchedulerFactory that you use to produce your scheduler instance.

WARNING

Never use a JobStore instance directly in your code. For some reason many people attempt to do this. +The JobStore is for behind-the-scenes use of Quartz itself. You have to tell Quartz (through configuration) which JobStore to use, +but then you should only work with the Scheduler interface in your code.

# RAMJobStore

RAMJobStore is the simplest JobStore to use, it is also the most performant (in terms of CPU time). +RAMJobStore gets its name in the obvious way: it keeps all of its data in RAM. This is why it's lightning-fast, +and also why it's so simple to configure. The drawback is that when your application ends (or crashes) all of +the scheduling information is lost - this means RAMJobStore cannot honor the setting of "non-volatility" on jobs and triggers. +For some applications this is acceptable - or even the desired behavior, but for other applications, this may be disasterous.

Configuring Quartz to use RAMJobStore

// this is actually the default, so you don't need to explicitly set this
+quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
+

To use RAMJobStore (and assuming you're using StdSchedulerFactory) you don't need to do anything special. Default configuration +of Quartz.NET uses RAMJobStore as job store implementation.

# ADO.NET Job Store (AdoJobStore)

AdoJobStore is also aptly named - it keeps all of its data in a database via ADO.NET. +Because of this it is a bit more complicated to configure than RAMJobStore, and it also is not as fast. +However, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.

To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use. +You can find table-creation SQL scripts in the "database/dbtables" directory of the Quartz.NET distribution. +If there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB. +One thing to note is that in these scripts, all the the tables start with the prefix QRTZ_ +(such as the tables QRTZ_TRIGGERS, and QRTZ_JOB_DETAIL). This prefix can actually be anything you'd like, as long as you inform AdoJobStore +what the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables, +for multiple scheduler instances, within the same database.

Currently the only option for the internal implementation of job store is JobStoreTXwhich creates transactions by itself. +This is different from Java version of Quartz where there is also option to choose JobStoreCMT which uses J2EE container +managed transactions.

The last piece of the puzzle is setting up a data source from which AdoJobStore can get connections to your database. +Data sources are defined in your Quartz.NET properties. Data source information contains the connection string +and ADO.NET delegate information.

# Configuring Quartz to use JobStoreTx

quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz
+

Next, you need to select a IDriverDelegate implementation for the JobStore to use. +The DriverDelegate is responsible for doing any ADO.NET work that may be needed for your specific database. +StdAdoDelegate is a delegate that uses "vanilla" ADO.NET code (and SQL statements) to do its work. +If there isn't another delegate made specifically for your database, try using this delegate - +special delegates usually have better performance or workarounds for database specific issues. +Other delegates can be found in the Quartz.Impl.AdoJobStore namespace, or in its sub-namespaces.

TIP

Quartz.NET will issue warning if you are using the default StdAdoDelegate as it has poor performance +when you have a lot of triggers to select from. Specific delegates have special SQL to limit result +set length (SqlServerDelegate uses TOP n, PostgreSQLDelegate LIMIT n, OracleDelegate ROWCOUNT() <= n etc.).

Once you've selected your delegate, set its class name as the delegate for AdoJobStore to use.

Configuring AdoJobStore to use a DriverDelegate

quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz
+

Next, you need to inform the JobStore what table prefix (discussed above) you are using.

Configuring AdoJobStore with the Table Prefix

quartz.jobStore.tablePrefix = QRTZ_
+

And finally, you need to set which data source should be used by the JobStore. The named data source must also be defined in your Quartz properties. +In this case, we're specifying that Quartz should use the data source name "myDS" (that is defined elsewhere in the configuration properties).

Configuring AdoJobStore with the name of the data source to use

quartz.jobStore.dataSource = myDS
+

One last thing that is needed for the configuration is to set data source connection string information and database provider. Connection +string is the standard ADO.NET connection which is driver specific. Database provider is an abstraction of database drivers to create +loose coupling between database drivers and Quartz.

Setting Data Source's Connection String And Database Provider

 quartz.dataSource.myDS.connectionString = Server=localhost;Database=quartz;Uid=quartznet;Pwd=quartznet
+ quartz.dataSource.myDS.provider = MySql
+

Currently following database providers are supported:

  • SqlServer - SQL Server driver +
    • For full framework this is by default System.Data.SqlClient (except in Quartz 3.1)
    • From Quartz 3.2 onwards for .NET Core this is by default Microsoft.Data.SqlClient
  • SystemDataSqlClient - Available separately on .NET Core (default for full framework)
  • MicrosoftDataSqlClient - Available separately on full framework (default for .NET Core)
  • OracleODP - Oracle's Oracle Driver
  • OracleODPManaged - Oracle's managed driver for Oracle 11
  • MySql - MySQL Connector/.NET
  • SQLite - SQLite ADO.NET Provider
  • SQLite-Microsoft - Microsoft SQLite ADO.NET Provider
  • Firebird - Firebird ADO.NET Provider
  • Npgsql - PostgreSQL Npgsql

TIP

There are many community contributed providers, like for NoSQL databases.

They are not supported by Quartz.NET project though.

You can and should use latest version of driver if newer is available, just create an assembly binding redirect

If your Scheduler is very busy (i.e. nearly always executing the same number of jobs as the size of the thread pool, then you should +probably set the number of connections in the data source to be the about the size of the thread pool + 1.This is commonly configured +int the ADO.NET connection string - see your driver implementation for details.

The quartz.jobStore.useProperties config parameter can be set to "true" (defaults to false) in order to instruct AdoJobStore that all values in JobDataMaps will be strings, +and therefore can be stored as name-value pairs, rather than storing more complex objects in their serialized form in the BLOB column. This is much safer in the long term, +as you avoid the class versioning issues that there are with serializing your non-String classes into a BLOB.

# Configuring AdoJobStore to use strings as JobDataMap values

TIP

This is recommended configuration because it greatly decreases the possibility of type serialization issues.

quartz.jobStore.useProperties = true
+

# Choosing a serializer

Quartz.NET supports both binary and JSON serialization. +JSON serialization comes from separate Quartz.Serialization.Json NuGet package.

TIP

JSON is recommended persistent format to store data in database for greenfield projects. +You should also strongly consider setting useProperties to true to restrict key-values to be strings.

// "json" is alias for "Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json" 
+quartz.serializer.type = json
+
+ + + diff --git a/documentation/quartz-3.x/tutorial/jobs-and-triggers.html b/documentation/quartz-3.x/tutorial/jobs-and-triggers.html new file mode 100644 index 000000000..5b1586239 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/jobs-and-triggers.html @@ -0,0 +1,108 @@ + + + + + + Jobs And Triggers | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# The Quartz API

The key interfaces and classes of the Quartz API are:

  • IScheduler - the main API for interacting with the scheduler.
  • IJob - an interface to be implemented by components that you wish to have executed by the scheduler.
  • IJobDetail - used to define instances of Jobs.
  • ITrigger - a component that defines the schedule upon which a given Job will be executed, job can have multiple associated triggers
  • JobBuilder - used to define/build JobDetail instances, which define instances of Jobs.
  • TriggerBuilder - used to define/build Trigger instances.
  • SchedulerBuilder - used to define/build scheduler instances, requires Quartz 3.1 or later.

In this tutorial for readability's sake following terms are used interchangeably: IScheduler and Scheduler, IJob and Job, IJobDetail and JobDetail, ITrigger and Trigger.

A Scheduler's life-cycle is bounded by it's creation, via a SchedulerFactory and a call to its Shutdown() method. +Once created the IScheduler interface can be used add, remove, and list Jobs and Triggers, and perform other scheduling-related operations (such as pausing a trigger). +However, the Scheduler will not actually act on any triggers (execute jobs) until it has been started with the Start() method, as shown in Lesson 1.

Quartz provides "builder" classes that define a Domain Specific Language (or DSL, also sometimes referred to as a "fluent interface"). In the previous lesson you saw an example of it, which we present a portion of here again:

// define the job and tie it to our HelloJob class
+IJobDetail job = JobBuilder.Create<HelloJob>()
+    .WithIdentity("myJob", "group1") // name "myJob", group "group1"
+    .Build();
+    
+// Trigger the job to run now, and then every 40 seconds
+ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("myTrigger", "group1")
+    .StartNow()
+    .WithSimpleSchedule(x => x
+        .WithIntervalInSeconds(40)
+        .RepeatForever())            
+    .Build();
+    
+// Tell quartz to schedule the job using our trigger
+await sched.scheduleJob(job, trigger);
+

The block of code that builds the job definition is using JobBuilder using fluent interface to create the product, IJobDetail. +Likewise, the block of code that builds the trigger is using TriggerBuilder's fluent interface and extension methods that are specific to given trigger type. +Possible schedule extension methods are:

  • WithCalendarIntervalSchedule
  • WithCronSchedule
  • WithDailyTimeIntervalSchedule
  • WithSimpleSchedule

The DateBuilder type contains various methods for easily constructing DateTimeOffset instances for particular points in time +(such as a date that represents the next even hour - or in other words 10:00:00 if it is currently 9:43:27).

# Jobs and Triggers

A job is a class that implements the IJob interface, which has only one simple method:

IJob Interface

namespace Quartz
+{
+    public interface IJob
+    {
+        Task Execute(JobExecutionContext context);
+    }
+}
+

When the Job's trigger fires (more on that in a moment), the Execute(..) method is invoked by one of the scheduler's worker threads. +The JobExecutionContext object that is passed to this method provides the job instance with information about its "run-time" environment - +a handle to the Scheduler that executed it, a handle to the Trigger that triggered the execution, the job's JobDetail object, and a few other items.

The JobDetail object is created by the Quartz.NET client (your program) at the time the Job is added to the scheduler. +It contains various property settings for the Job, as well as a JobDataMap, which can be used to store state information for a given instance of your job class. +It is essentially the definition of the job instance, and is discussed in further detail in the next lesson.

Trigger objects are used to trigger the execution (or 'firing') of jobs. When you wish to schedule a job, you instantiate a trigger and 'tune' its properties +to provide the scheduling you wish to have. Triggers may also have a JobDataMap associated with them - this is useful to passing parameters to a +Job that are specific to the firings of the trigger. Quartz ships with a handful of different trigger types, but the most commonly used types +are SimpleTrigger (interface ISimpleTrigger) and CronTrigger (interface ICronTrigger).

SimpleTrigger is handy if you need 'one-shot' execution (just single execution of a job at a given moment in time), or if you need to fire a job at a given time, +and have it repeat N times, with a delay of T between executions. CronTrigger is useful if you wish to have triggering based on calendar-like schedules - +such as "every Friday, at noon" or "at 10:15 on the 10th day of every month."

Why Jobs AND Triggers? Many job schedulers do not have separate notions of jobs and triggers. Some define a 'job' as simply an execution time (or schedule) +along with some small job identifier. Others are much like the union of Quartz's job and trigger objects. While developing Quartz, we decided that it made sense +to create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits.

For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job. +Another benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired, +so that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define +its associated job.

# Identities

Jobs and Triggers are given identifying keys as they are registered with the Quartz scheduler. +The keys of Jobs and Triggers (JobKey and TriggerKey) allow them to be placed into 'groups' which can be useful for organizing your jobs and +triggers into categories such as "reporting jobs" and "maintenance jobs". The name portion of the key of a job or trigger must be unique within the group

  • or in other words, the complete key (or identifier) of a job or trigger is the compound of the name and group.

You now have a general idea about what Jobs and Triggers are, you can learn more about them in +Lesson 3: More About Jobs & JobDetails and Lesson 4: More About Triggers

+ + + diff --git a/documentation/quartz-3.x/tutorial/miscellaneous-features.html b/documentation/quartz-3.x/tutorial/miscellaneous-features.html new file mode 100644 index 000000000..b56dc6c1d --- /dev/null +++ b/documentation/quartz-3.x/tutorial/miscellaneous-features.html @@ -0,0 +1,70 @@ + + + + + + Miscellaneous Features | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Plug-Ins

Quartz provides an interface (ISchedulerPlugin) for plugging-in additional functionality.

Plugins that ship with Quartz to provide various utility capabilities can be found documented in the Quartz.Plugins namespace. +They provide functionality such as auto-scheduling of jobs upon scheduler startup, logging a history of job and trigger events, +and ensuring that the scheduler shuts down cleanly when the virtual machine exits.

# JobFactory

When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler. +The default JobFactory simply activates a new instance of the job class. You may want to create your own implementation +of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.

See the IJobFactory interface, and the associated IScheduler.JobFactory setter property.

TIP

Since Quartz 3.1, there's built-in support for integrating with Microsoft Dependency Injection which in +turn allows to use different IoC container implementations.

# 'Factory-Shipped' Jobs

Quartz also provides a number of utility Jobs that you can use in your application for doing things like sending +e-mails and invoking remote objects. These out-of-the-box Jobs can be found documented in the Quartz.Jobs namespace and +are part of the Quartz.Jobs NuGet package (opens new window).

+ + + diff --git a/documentation/quartz-3.x/tutorial/more-about-jobs.html b/documentation/quartz-3.x/tutorial/more-about-jobs.html new file mode 100644 index 000000000..02614fae5 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/more-about-jobs.html @@ -0,0 +1,193 @@ + + + + + + More About Jobs & JobDetails | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

As you saw in Lesson 2, jobs are rather easy to implement. There are just a few more things that you need to understand about +the nature of jobs, about the Execute(..) method of the IJob interface, and about JobDetails.

While a job class that you implement has the code that knows how to do the actual work +of the particular type of job, Quartz.NET needs to be informed about various attributes +that you may wish an instance of that job to have. This is done via the JobDetail class, +which was mentioned briefly in the previous section.

JobDetail instances are built using the JobBuilder class. JobBuilder allows you to describe +your job's details using a fluent interface.

Let's take a moment now to discuss a bit about the 'nature' of jobs and the life-cycle of job instances within Quartz.NET. +First lets take a look back at some of that snippet of code we saw in Lesson 1:

Using Quartz.NET

// define the job and tie it to our HelloJob class
+IJobDetail job = JobBuilder.Create<HelloJob>()
+	.WithIdentity("myJob", "group1")
+	.Build();
+
+// Trigger the job to run now, and then every 40 seconds
+ITrigger trigger = TriggerBuilder.Create()
+  .WithIdentity("myTrigger", "group1")
+  .StartNow()
+  .WithSimpleSchedule(x => x
+	  .WithIntervalInSeconds(40)
+	  .RepeatForever())
+  .Build();
+  
+sched.ScheduleJob(job, trigger);
+

Now consider the job class HelloJob defined as such:

public class HelloJob : IJob
+{
+	public async Task Execute(IJobExecutionContext context)
+	{
+		await Console.Out.WriteLineAsync("HelloJob is executing.");
+	}
+}
+

Notice that we give the scheduler a IJobDetail instance, and that it refers to the job to be executed by simply +providing the job's class. Each (and every) time the scheduler executes the job, it creates a new instance of the +class before calling its Execute(..) method. One of the ramifications of this behavior is the fact that jobs must +have a no-arguement constructor. Another ramification is that it does not make sense to have data-fields defined +on the job class - as their values would not be preserved between job executions.

You may now be wanting to ask "how can I provide properties/configuration for a Job instance?" and "how can I +keep track of a job's state between executions?" The answer to these questions are the same: the key is the JobDataMap, +which is part of the JobDetail object.

# JobDataMap

The JobDataMap can be used to hold any number of (serializable) objects which you wish to have made available +to the job instance when it executes. JobDataMap is an implementation of the IDictionary interface, and has +some added convenience methods for storing and retrieving data of primitive types.

Here's some quick snippets of putting data into the JobDataMap prior to adding the job to the scheduler:

Setting Values in a JobDataMap

// define the job and tie it to our DumbJob class
+IJobDetail job = JobBuilder.Create<DumbJob>()
+	.WithIdentity("myJob", "group1") // name "myJob", group "group1"
+	.UsingJobData("jobSays", "Hello World!")
+	.UsingJobData("myFloatValue", 3.141f)
+	.Build();
+

Here's a quick example of getting data from the JobDataMap during the job's execution:

Getting Values from a JobDataMap

public class DumbJob : IJob
+{
+	public async Task Execute(IJobExecutionContext context)
+	{
+		JobKey key = context.JobDetail.Key;
+
+		JobDataMap dataMap = context.JobDetail.JobDataMap;
+
+		string jobSays = dataMap.GetString("jobSays");
+		float myFloatValue = dataMap.GetFloat("myFloatValue");
+
+		await Console.Error.WriteLineAsync("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
+	}
+}
+

If you use a persistent JobStore (discussed in the JobStore section of this tutorial) you should use some care +in deciding what you place in the JobDataMap, because the object in it will be serialized, and they therefore +become prone to class-versioning problems. Obviously standard .NET types should be very safe, but beyond that, +any time someone changes the definition of a class for which you have serialized instances, +care has to be taken not to break compatibility.

Optionally, you can put AdoJobStore and JobDataMap into a mode where only primitives +and strings can be stored in the map, thus eliminating any possibility of later serialization problems.

If you add properties with set accessor to your job class that correspond to the names of keys in the JobDataMap, +then Quartz's default JobFactory implementation will automatically call those setters when the job is instantiated, +thus preventing the need to explicitly get the values out of the map within your execute method. Note this +functionality is not maintained by default when using a custom JobFactory.

Triggers can also have JobDataMaps associated with them. This can be useful in the case where you have a Job that is stored in the scheduler +for regular/repeated use by multiple Triggers, yet with each independent triggering, you want to supply the Job with different data inputs.

The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge of the JobDataMap +found on the JobDetail and the one found on the Trigger, with the values in the latter overriding any same-named values in the former.

Here's a quick example of getting data from the JobExecutionContext's merged JobDataMap during the job's execution:

public class DumbJob : IJob
+{
+	public async Task Execute(IJobExecutionContext context)
+	{
+		JobKey key = context.JobDetail.Key;
+
+		JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
+
+		string jobSays = dataMap.GetString("jobSays");
+		float myFloatValue = dataMap.GetFloat("myFloatValue");
+		IList<DateTimeOffset> state = (IList<DateTimeOffset>)dataMap["myStateData"];
+		state.Add(DateTimeOffset.UtcNow);
+
+		await Console.Error.WriteLineAsync("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
+	}
+}
+

Or if you wish to rely on the JobFactory "injecting" the data map values onto your class, it might look like this instead:

public class DumbJob : IJob
+{
+	public string JobSays { private get; set; }
+	public float MyFloatValue { private get; set; }
+
+	public async Task Execute(IJobExecutionContext context)
+	{
+		JobKey key = context.JobDetail.Key;
+
+		JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
+
+		IList<DateTimeOffset> state = (IList<DateTimeOffset>)dataMap["myStateData"];
+		state.Add(DateTimeOffset.UtcNow);
+
+		await Console.Error.WriteLineAsync("Instance " + key + " of DumbJob says: " + JobSays + ", and val is: " + MyFloatValue);
+	}
+}
+

You'll notice that the overall code of the class is longer, but the code in the Execute() method is cleaner. +One could also argue that although the code is longer, that it actually took less coding, if the programmer's IDE was used to auto-generate the properties, +rather than having to hand-code the individual calls to retrieve the values from the JobDataMap. The choice is yours.

# Job "Instances"

Many users spend time being confused about what exactly constitutes a "job instance". +We'll try to clear that up here and in the section below about job state and concurrency.

You can create a single job class, and store many 'instance definitions' of it within the scheduler by creating multiple instances of JobDetails

  • each with its own set of properties and JobDataMap - and adding them all to the scheduler.

For example, you can create a class that implements the IJob interface called "SalesReportJob". +The job might be coded to expect parameters sent to it (via the JobDataMap) to specify the name of the sales person that the sales +report should be based on. They may then create multiple definitions (JobDetails) of the job, such as "SalesReportForJoe" +and "SalesReportForMike" which have "joe" and "mike" specified in the corresponding JobDataMaps as input to the respective jobs.

When a trigger fires, the JobDetail (instance definition) it is associated to is loaded, +and the job class it refers to is instantiated via the JobFactory configured on the Scheduler. +The default JobFactory simply calls the default constructor of the job class using Activator.CreateInstance, +then attempts to call setter properties on the class that match the names of keys within the JobDataMap. +You may want to create your own implementation of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance.

In "Quartz speak", we refer to each stored JobDetail as a "job definition" or "JobDetail instance", +and we refer to a each executing job as a "job instance" or "instance of a job definition". +Usually if we just use the word "job" we are referring to a named definition, or JobDetail. +When we are referring to the class implementing the job interface, we usually use the term "job type".

# Job State and Concurrency

Now, some additional notes about a job's state data (aka JobDataMap) and concurrency. +There are a couple attributes that can be added to your Job class that affect Quartz's behaviour with respect to these aspects.

[DisallowConcurrentExecution] is an attribute that can be added to the Job class that tells Quartz not to execute multiple instances +of a given job definition (that refers to the given job class) concurrently. +Notice the wording there, as it was chosen very carefully. In the example from the previous section, if "SalesReportJob" has this attribute, +then only one instance of "SalesReportForJoe" can execute at a given time, but it can execute concurrently with an instance of "SalesReportForMike". +The constraint is based upon an instance definition (JobDetail), not on instances of the job class. +However, it was decided (during the design of Quartz) to have the attribute carried on the class itself, because it does often make a difference to how the class is coded.

[PersistJobDataAfterExecution] is an attribute that can be added to the Job class that tells Quartz to update the stored copy of +the JobDetail's JobDataMap after the Execute() method completes successfully (without throwing an exception), such that the next +execution of the same job (JobDetail) receives the updated values rather than the originally stored values. +Like the [DisallowConcurrentExecution] attribute, this applies to a job definition instance, not a job class instance, +though it was decided to have the job class carry the attribute because it does often make a difference to how the class is coded +(e.g. the 'statefulness' will need to be explicitly 'understood' by the code within the execute method).

If you use the PersistJobDataAfterExecution attribute, you should strongly consider also using the [DisallowConcurrentExecution] attribute, +in order to avoid possible confusion (race conditions) of what data was left stored when two instances of the same job (JobDetail) executed concurrently.

# Other Attributes Of Jobs

Here's a quick summary of the other properties which can be defined for a job instance via the JobDetail object:

  • Durability - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it. +In other words, non-durable jobs have a life span bounded by the existence of its triggers.
  • RequestsRecovery - if a job "requests recovery", and it is executing during the time of a 'hard shutdown' of the scheduler +(i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. +In this case, the JobExecutionContext.Recovering property will return true.

# JobExecutionException

Finally, we need to inform you of a few details of the IJob.Execute(..) method. The only type of exception +that you should throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire contents of the +execute method with a 'try-catch' block. You should also spend some time looking at the documentation for the JobExecutionException, +as your job can use it to provide the scheduler various directives as to how you want the exception to be handled.

+ + + diff --git a/documentation/quartz-3.x/tutorial/more-about-triggers.html b/documentation/quartz-3.x/tutorial/more-about-triggers.html new file mode 100644 index 000000000..0ac3bea33 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/more-about-triggers.html @@ -0,0 +1,127 @@ + + + + + + More About Triggers | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Like jobs, triggers are relatively easy to work with, but do contain a variety of customizable options that you need to +be aware of and understand before you can make full use of Quartz.NET. Also, as noted earlier, there are different types of triggers, +that you can select to meet different scheduling needs.

# Common Trigger Attributes

Aside from the fact that all trigger types have TriggerKey properties for tracking their identities, +there are a number of other properties that are common to all trigger types. These common properties are set using the TriggerBuilder +when you are building the trigger definition (examples of that will follow).

Here is a listing of properties common to all trigger types:

  • The JobKey property indicates the identity of the job that should be executed when the trigger fires.
  • The StartTimeUtc property indicates when the trigger's schedule first comes into affect. +The value is a DateTimeOffset object that defines a moment in time on a given calendar date. +For some trigger types, the trigger will actually fire at the start time, for others it simply marks the time that the schedule should start being followed. +This means you can store a trigger with a schedule such as "every 5th day of the month" during January, and if the StartTimeUtc property is set to April 1st, +it will be a few months before the first firing.
  • The EndTimeUtc property indicates when the trigger's schedule should no longer be in effect. +In other words, a trigger with a schedule of "every 5th day of the month" and with an end time of July 1st will fire for it's last time on June 5th.

Other properties, which take a bit more explanation are discussed in the following sub-sections.

# Priority

Sometimes, when you have many Triggers (or few worker threads in your Quartz.NET thread pool), Quartz.NET may not have enough resources to immediately fire all +of the Triggers that are scheduled to fire at the same time. In this case, you may want to control which of your Triggers get first crack at the available Quartz.NET worker threads. +For this purpose, you can set the priority property on a Trigger. If N Triggers are to fire at the same time, but there are only Z worker threads currently available, +then the first Z Triggers with the highest priority will be executed first. If you do not set a priority on a Trigger, then it will use the default priority of 5. +Any integer value is allowed for priority, positive or negative. A larger number indicates a higher priority. i.e. A trigger with a Priority of 7 will have priority over trigger with a value of 5.

TIP

Priorities are only compared when triggers have the same fire time. A trigger scheduled to fire at 10:59 will always fire before one scheduled to fire at 11:00.

TIP

When a trigger's job is detected to require recovery, its recovery is scheduled with the same priority as the original trigger.

# Misfire Instructions

Another important property of a Trigger is its "misfire instruction". A misfire occurs if a persistent trigger "misses" its firing time because of the scheduler being shutdown, +or because there are no available threads in Quartz.NET's thread pool for executing the job. +The different trigger types have different misfire instructions available to them. +By default they use a 'smart policy' instruction - which has dynamic behavior based on trigger type and configuration. +When the scheduler starts, it searches for any persistent triggers that have misfired, and it then updates each of them based on their individually +configured misfire instructions. When you start using Quartz.NET in your own projects, you should make yourself familiar with the misfire instructions +that are defined on the given trigger types, and explained in their API documentation. More specific information about misfire instructions will be given within +the tutorial lessons specific to each trigger type.

# Calendars

Quartz.NET Calendar objects implementing ICalendar interface can be associated with triggers at the time the trigger is stored in the scheduler. +Calendars are useful for excluding blocks of time from the trigger's firing schedule. For instance, you could +create a trigger that fires a job every weekday at 9:30 am, but then add a Calendar that excludes all of the business's holidays.

Calendar's can be any serializable objects that implement the ICalendar interface, which looks like this:

namespace Quartz
+{
+	public interface ICalendar
+	{
+		string Description { get; set; }
+
+		ICalendar CalendarBase { set; get; }
+
+		bool IsTimeIncluded(DateTimeOffset timeUtc);
+
+		DateTime GetNextIncludedTimeUtc(DateTimeOffset timeUtc);
+
+		ICalendar Clone();
+	}
+} 
+

Even though calendars can 'block out' sections of time as narrow as a millisecond, most likely, you'll be interested in +'blocking-out' entire days. As a convenience, Quartz.NET includes the class HolidayCalendar, which does just that.

Calendars must be instantiated and registered with the scheduler via the AddCalendar(..) method. If you use HolidayCalendar, +after instantiating it, you should use its AddExcludedDate(DateTime date) method in order to populate it with the days you wish +to have excluded from scheduling. The same calendar instance can be used with multiple triggers such as this:

Calendar Example

    HolidayCalendar cal = new HolidayCalendar();
+    cal.AddExcludedDate(someDate);
+    
+    await sched.AddCalendar("myHolidays", cal, false);
+    
+	ITrigger t = TriggerBuilder.Create()
+		.WithIdentity("myTrigger")
+		.ForJob("myJob")
+		.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
+		.ModifiedByCalendar("myHolidays") // but not on holidays
+		.Build();
+
+	// .. schedule job with trigger
+
+	ITrigger t2 = TriggerBuilder.Create()
+		.WithIdentity("myTrigger2")
+		.ForJob("myJob2")
+		.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
+		.ModifiedByCalendar("myHolidays") // but not on holidays
+		.Build();
+    
+    // .. schedule job with trigger2 
+

The details of the construction/building of triggers will be given in the next couple lessons. +For now, just believe that the code above creates two triggers, each scheduled to fire daily. +However, any of the firings that would have occurred during the period excluded by the calendar will be skipped.

See the Quartz.Impl.Calendar namespace for a number of ICalendar implementations that may suit your needs.

+ + + diff --git a/documentation/quartz-3.x/tutorial/scheduler-listeners.html b/documentation/quartz-3.x/tutorial/scheduler-listeners.html new file mode 100644 index 000000000..e5dcd0d02 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/scheduler-listeners.html @@ -0,0 +1,89 @@ + + + + + + Scheduler Listeners | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

SchedulerListeners are much like ITriggerListeners and IJobListeners, except they receive notification of +events within the scheduler itself - not necessarily events related to a specific trigger or job.

Scheduler-related events include: the addition of a job/trigger, the removal of a job/trigger, a serious error +within the scheduler, notification of the scheduler being shutdown, and others.

WARNING

Make sure your scheduler listeners never throw an exception (use a try-catch) and that they can handle internal problems. +Quartz can get in unpredictable state when it is unable to determine whether required logic in listener was completed successfully when listener notification failed.

The ISchedulerListener Interface

public interface ISchedulerListener
+{
+	Task JobScheduled(Trigger trigger);
+
+	Task JobUnscheduled(string triggerName, string triggerGroup);
+
+	Task TriggerFinalized(Trigger trigger);
+
+	Task TriggersPaused(string triggerName, string triggerGroup);
+
+	Task TriggersResumed(string triggerName, string triggerGroup);
+
+	Task JobsPaused(string jobName, string jobGroup);
+
+	Task JobsResumed(string jobName, string jobGroup);
+
+	Task SchedulerError(string msg, SchedulerException cause);
+
+	Task SchedulerShutdown();
+} 
+

SchedulerListeners are registered with the scheduler's ListenerManager. +SchedulerListeners can be virtually any object that implements the ISchedulerListener interface.

Adding a SchedulerListener:

scheduler.ListenerManager.AddSchedulerListener(mySchedListener);
+

Removing a SchedulerListener:

scheduler.ListenerManager.RemoveSchedulerListener(mySchedListener);
+
+ + + diff --git a/documentation/quartz-3.x/tutorial/simpletriggers.html b/documentation/quartz-3.x/tutorial/simpletriggers.html new file mode 100644 index 000000000..cd15b5d46 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/simpletriggers.html @@ -0,0 +1,128 @@ + + + + + + SimpleTrigger | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time, +or at a specific moment in time followed by repeats at a specific interval. Or plainer english, if you want the trigger to +fire at exactly 11:23:54 AM on January 13, 2005, and then fire five more times, every ten seconds.

With this description, you may not find it surprising to find that the properties of a SimpleTrigger include: a start-time, +and end-time, a repeat count, and a repeat interval. All of these properties are exactly what you'd expect them to be, with +only a couple special notes related to the end-time property.

The repeat count can be zero, a positive integer, or the constant value SimpleTrigger.RepeatIndefinitely. +The repeat interval property must be TimeSpan.Zero, or a positive TimeSpan value. +Note that a repeat interval of zero will cause 'repeat count' firings of the trigger to happen concurrently +(or as close to concurrently as the scheduler can manage).

If you're not already familiar with the DateTime class, you may find it helpful for computing your trigger fire-times, +depending on the startTimeUtc (or endTimeUtc) that you're trying to create.

The EndTimeUtc property (if it is specified) over-rides the repeat count property. This can be useful if you wish to create a trigger +such as one that fires every 10 seconds until a given moment in time - rather than having to compute the number of times it would +repeat between the start-time and the end-time, you can simply specify the end-time and then use a repeat count of RepeatIndefinitely +(you could even specify a repeat count of some huge number that is sure to be more than the number of times the trigger will actually +fire before the end-time arrives).

SimpleTrigger instances are built using TriggerBuilder (for the trigger's main properties) and WithSimpleSchedule extension method +(for the SimpleTrigger-specific properties).

Build a trigger for a specific moment in time, with no repeats:

// trigger builder creates simple trigger by default, actually an ITrigger is returned
+ISimpleTrigger trigger = (ISimpleTrigger) TriggerBuilder.Create()
+    .WithIdentity("trigger1", "group1")
+    .StartAt(myStartTime) // some Date 
+    .ForJob("job1", "group1") // identify job with name, group strings
+    .Build();
+

Build a trigger for a specific moment in time, then repeating every ten seconds ten times:

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger3", "group1")
+    .StartAt(myTimeToStartFiring) // if a start time is not given (if this line were omitted), "now" is implied
+    .WithSimpleSchedule(x => x
+        .WithIntervalInSeconds(10)
+        .WithRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
+    .ForJob(myJob) // identify job with handle to its JobDetail itself                   
+    .Build();
+
+

Build a trigger that will fire once, five minutes in the future:

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger5", "group1")
+    .StartAt(DateBuilder.FutureDate(5, IntervalUnit.Minute)) // use DateBuilder to create a date in the future
+    .ForJob(myJobKey) // identify job with its JobKey
+    .Build();
+

Build a trigger that will fire now, then repeat every five minutes, until the hour 22:00:

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger7", "group1")
+    .WithSimpleSchedule(x => x
+        .WithIntervalInMinutes(5)
+        .RepeatForever())
+    .EndAt(DateBuilder.DateOf(22, 0, 0))
+    .Build();
+

Build a trigger that will fire at the top of the next hour, then repeat every 2 hours, forever:

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
+    .StartAt(DateBuilder.EvenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
+    .WithSimpleSchedule(x => x
+        .WithIntervalInHours(2)
+        .RepeatForever())
+    // note that in this example, 'forJob(..)' is not called 
+    //  - which is valid if the trigger is passed to the scheduler along with the job  
+    .Build();
+
+await scheduler.scheduleJob(trigger, job);
+

Spend some time looking at all of the available methods in the language defined by TriggerBuilder and its extension method WithSimpleSchedule +so that you can be familiar with options available to you that may not have been demonstrated in the examples above.

# SimpleTrigger Misfire Instructions

SimpleTrigger has several instructions that can be used to inform Quartz.NET what it should do when a misfire occurs. +(Misfire situations were introduced in the More About Triggers section of this tutorial). +These instructions are defined as constants on MisfirePolicy.SimpleTrigger (including API documentation describing their behavior). +The instructions include:

Misfire Instruction Constants for SimpleTrigger

  • MisfireInstruction.IgnoreMisfirePolicy
  • MisfirePolicy.SimpleTrigger.FireNow
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithExistingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithRemainingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithRemainingCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithExistingCount

You should recall from the earlier lessons that all triggers have the MisfirePolicy.SmartPolicy instruction available for use, +and this instruction is also the default for all trigger types.

If the 'smart policy' instruction is used, SimpleTrigger dynamically chooses between its various MISFIRE instructions, based on the configuration +and state of the given SimpleTrigger instance. The documentation for the SimpleTrigger.UpdateAfterMisfire() method explains the exact details of +this dynamic behavior.

When building SimpleTriggers, you specify the misfire instruction as part of the simple schedule (via SimpleSchedulerBuilder):

ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("trigger7", "group1")
+    .WithSimpleSchedule(x => x
+        .WithIntervalInMinutes(5)
+        .RepeatForever()
+        .WithMisfireHandlingInstructionNextWithExistingCount())
+    .Build();
+
+ + + diff --git a/documentation/quartz-3.x/tutorial/trigger-and-job-listeners.html b/documentation/quartz-3.x/tutorial/trigger-and-job-listeners.html new file mode 100644 index 000000000..09c62694c --- /dev/null +++ b/documentation/quartz-3.x/tutorial/trigger-and-job-listeners.html @@ -0,0 +1,99 @@ + + + + + + Trigger and Job Listeners | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Listeners are objects that you create to perform actions based on events occuring within the scheduler. +As you can probably guess, TriggerListeners receive events related to triggers, and JobListeners receive events related to jobs.

Trigger-related events include: trigger firings, trigger mis-firings (discussed in the "Triggers" section of this document), +and trigger completions (the jobs fired off by the trigger is finished).

WARNING

Make sure your trigger and job listeners never throw an exception (use a try-catch) and that they can handle internal problems. +Jobs can get stuck after Quartz is unable to determine whether required logic in listener was completed successfully when listener notification failed.

The ITriggerListener Interface

public interface ITriggerListener
+{
+	 string Name { get; }
+	 
+	 Task TriggerFired(ITrigger trigger, IJobExecutionContext context);
+	 
+	 Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context);
+	 
+	 Task TriggerMisfired(ITrigger trigger);
+	 
+	 Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, int triggerInstructionCode);
+}
+

Job-related events include: a notification that the job is about to be executed, and a notification when the job has completed execution.

The IJobListener Interface

public interface IJobListener
+{
+	string Name { get; }
+
+	Task JobToBeExecuted(IJobExecutionContext context);
+
+	Task JobExecutionVetoed(IJobExecutionContext context);
+
+	Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException);
+} 
+

# Using Your Own Listeners

To create a listener, simply create an object the implements either the ITriggerListener and/or IJobListener interface. +Listeners are then registered with the scheduler during run time, and must be given a name (or rather, they must advertise their own +name via their Name property.

For your convenience, rather than implementing those interfaces, your class could also extend the class JobListenerSupport or TriggerListenerSupport +and simply override the events you're interested in.

Listeners are registered with the scheduler's ListenerManager along with a Matcher that describes which Jobs/Triggers the listener wants to receive events for.

TIP

Listeners are registered with the scheduler during run time, and are NOT stored in the JobStore along with the jobs and triggers. +This is because listeners are typically an integration point with your application. +Hence, each time your application runs, the listeners need to be re-registered with the scheduler.

Adding a JobListener that is interested in a particular job:

scheduler.ListenerManager.AddJobListener(myJobListener, KeyMatcher<JobKey>.KeyEquals(new JobKey("myJobName", "myJobGroup")));
+

Adding a JobListener that is interested in all jobs of a particular group:

scheduler.ListenerManager.AddJobListener(myJobListener, GroupMatcher<JobKey>.GroupEquals("myJobGroup"));
+

Adding a JobListener that is interested in all jobs of two particular groups:

scheduler.ListenerManager.AddJobListener(myJobListener,
+	OrMatcher<JobKey>.Or(GroupMatcher<JobKey>.GroupEquals("myJobGroup"), GroupMatcher<JobKey>.GroupEquals("yourGroup")));
+

Adding a JobListener that is interested in all jobs:

scheduler.ListenerManager.AddJobListener(myJobListener, GroupMatcher<JobKey>.AnyGroup());
+

Listeners are not used by most users of Quartz.NET, but are handy when application requirements create the need +for the notification of events, without the Job itself explicitly notifying the application.

+ + + diff --git a/documentation/quartz-3.x/tutorial/using-quartz.html b/documentation/quartz-3.x/tutorial/using-quartz.html new file mode 100644 index 000000000..127ab42f9 --- /dev/null +++ b/documentation/quartz-3.x/tutorial/using-quartz.html @@ -0,0 +1,121 @@ + + + + + + Using Quartz | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

Before you can use the scheduler, it needs to be instantiated (who'd have guessed?). +To do this, you use an implementor of ISchedulerFactory.

Once a scheduler is instantiated, it can be started, placed in stand-by mode, and shutdown. +Note that once a scheduler is shutdown, it cannot be restarted without being re-instantiated. +Triggers do not fire (jobs do not execute) until the scheduler has been started, nor while it is +in the paused state.

Here's a quick snippet of code, that instantiates and starts a scheduler, and schedules a job for execution:

Using Quartz.NET

// construct a scheduler factory using defaults
+StdSchedulerFactory factory = new StdSchedulerFactory();
+
+// get a scheduler
+IScheduler scheduler = await factory.GetScheduler();
+await scheduler.Start();
+
+// define the job and tie it to our HelloJob class
+IJobDetail job = JobBuilder.Create<HelloJob>()
+    .WithIdentity("myJob", "group1")
+    .Build();
+
+// Trigger the job to run now, and then every 40 seconds
+ITrigger trigger = TriggerBuilder.Create()
+    .WithIdentity("myTrigger", "group1")
+    .StartNow()
+    .WithSimpleSchedule(x => x
+        .WithIntervalInSeconds(40)
+        .RepeatForever())
+.Build();
+    
+await scheduler.ScheduleJob(job, trigger);
+
+// You could also schedule multiple triggers for the same job with
+// await scheduler.ScheduleJob(job, new List<ITrigger>() { trigger1, trigger2 }, replace: true);
+

Configuring scheduler with fluent API

You can also use SchedulerBuilder fluent API to programmatically configure different aspects of the scheduler.

var sched = await SchedulerBuilder.Create()
+    // default max concurrency is 10
+    .UseDefaultThreadPool(x => x.MaxConcurrency = 5)
+    // this is the default 
+    // .WithMisfireThreshold(TimeSpan.FromSeconds(60))
+    .UsePersistentStore(x =>
+    {
+        // force job data map values to be considered as strings
+        // prevents nasty surprises if object is accidentally serialized and then 
+        // serialization format breaks, defaults to false
+        x.UseProperties = true;
+        x.UseClustering();
+        x.UseSqlServer("my connection string");
+        // this requires Quartz.Serialization.Json NuGet package
+        x.UseJsonSerializer();
+    })
+    // job initialization plugin handles our xml reading, without it defaults are used
+    // requires Quartz.Plugins NuGet package
+    .UseXmlSchedulingConfiguration(x =>
+    {
+        x.Files = new[] { "~/quartz_jobs.xml" };
+        // this is the default
+        x.FailOnFileNotFound = true;
+        // this is not the default
+        x.FailOnSchedulingError = true;
+    })
+    .BuildScheduler();
+
+await scheduler.Start();
+

As you can see, working with Quartz.NET is rather simple. In Lesson 2 we'll give a quick overview of Jobs and Triggers, so that you can more fully understand this example.

+ + + diff --git a/download.html b/download.html new file mode 100644 index 000000000..c00bdbbf7 --- /dev/null +++ b/download.html @@ -0,0 +1,56 @@ + + + + + + Download Quartz.NET | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faq.html b/faq.html new file mode 100644 index 000000000..f7a3fe91b --- /dev/null +++ b/faq.html @@ -0,0 +1,31 @@ + + + + + + FAQ | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/favicon-16x16.png b/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..c928562bf2881e03be7a44d57cd885253f84e608 GIT binary patch literal 1665 zcmZ{k3s4hB7{@oDNEM2r^#LTgBnGUQABzH+h@(>OYm6j1? zCZZzZ6QR~eeN?~^1Vymz6d%(T84C<8mOfO9ia;6b3&he5wwf|^=k|8L`+nbl|9iJ{ zc2#_|=VYJB007SzMWh;zQytyi72fCZyb|Cr!4R$t2jE=Mlo9Pj7}GM;(Q;7L;`aas zh)$ta0Xm6PfGBeAgU8D~yZ^T8IWNcvJNX z^J98gLIUd69{RP>e6xJIl0OcBCiB}rUwy48q<#aah;^78D?D@O>f(ltE3fW=p2wBI zkj+HyJsn7Bvgfp(fC}KaV)DmwHk;*4)^vZDd}TZH9Ko(OP%VdxJFDHPU^d*#zy1e@ zpB(CHSo&2Sr^cxLwuIW8#ilb}XW^u!r_<83Ur@g;?sRroL^#XG&pG>QPMv-X>k{^yUJvv3aIv%ep5xT{gqWVd%zjmyIDz)$tN zeyr(!+W$KB;Mriu;9ck(?i#jfXI2GQ+Tf%ww{;Yrk{U`K?>K&MZ7x9vZ@(P*dDjBk zL}IwTuKw1G&Lo#Ve=sb=5yray6~8TsQUuIQkQ(l?hDbk}u2$elty>&%zsSF*+U>8J zP)2;`E_ZL?jh3nBnb?(~=X<&HTW)wsz1K9qJR5tjYPUIp{>kIsVH5usB|euMA}jkN zbk#sccur5>!`d0H$#pFUW>wehp}0)1WcDr$>&RF+@PJ62Ltcp^|`FFVvwIjP~~{tHEC z4{r$-iSla6+y!}t6cy?ktuQ7Biy|WR8nGd+ujk_P{42-1XOM1N+jGTLkGD5h^p$lr zj<}F+++(NYmV%>qcDGhP+O{-^ESSHe*C&bb;TN|q4HsPV|A5{3?NNu1l+#BY@yPu1_7yEZ_-&U8G<(-Mj(}lFtJ`I t)rqxQk`T)XR3?^SI=xhsDwG9dIzFu6Lw{%EOXk59KulD8WR*N+%ij)ZFnIs~ literal 0 HcmV?d00001 diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..bd7c22db23924c2d72ba591addcf5738923edae3 GIT binary patch literal 2721 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 a>IgG*g#DG+rK<}o04sAlvj?W$r~eH_Hn%wd literal 0 HcmV?d00001 diff --git a/favicon-96x96.png b/favicon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..9403db8c95de60271ec43dfeec7075a94ee09d46 GIT binary patch literal 11073 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 + + + + + Quartz.NET Features | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

# Runtime Environments

  • Quartz.NET can run embedded within another free standing application
  • Quartz.NET can run as a stand-alone program (within its own .NET virtual machine instance), to be used via .NET Remoting
  • Quartz.NET can be instantiated as a cluster of stand-alone programs (with load-balance and fail-over capabilities)

# Job Scheduling

Jobs are scheduled to run when a given Trigger occurs. Triggers can be created with nearly any combination of the following directives:

  • at a certain time of day (to the millisecond)
  • on certain days of the week
  • on certain days of the month
  • on certain days of the year
  • not on certain days listed within a registered Calendar (such as business holidays)
  • repeated a specific number of times
  • repeated until a specific time/date
  • repeated indefinitely
  • repeated with a delay interval

Jobs are given names by their creator and can also be organized into named groups. +Triggers may also be given names and placed into groups, in order to easily organize them within the scheduler. +Jobs can be added to the scheduler once, but registered with multiple Triggers.

# Job Execution

  • Jobs can be any .NET class that implements the simple IJob interface, leaving infinite possibilities for the work Jobs can perform.
  • Job class instances can be instantiated by Quartz.NET, or by your application's framework.
  • When a Trigger occurs, the scheduler notifies zero or more .NET objects implementing the JobListener and TriggerListener interfaces. These listeners are also notified after the Job has executed.
  • As Jobs are completed, they return a JobCompletionCode which informs the scheduler of success or failure. The JobCompletionCode can also instruct the scheduler of any actions it should take based on the success/fail code - such as immediate re-execution of the Job.

# Job Persistence

  • The design of Quartz.NET includes a IJobStore interface that can be implemented to provide various mechanisms for the storage of jobs.
  • With the use of the included AdoJobStore, all Jobs and Triggers configured as "non-volatile" are stored in a relational database via ADO.NET.
  • With the use of the included RAMJobStore, all Jobs and Triggers are stored in RAM and therefore do not persist between program executions - but this has the advantage of not requiring an external database.

# Clustering

  • Fail-over.
  • Load balancing.

# Listeners & Plug-Ins

  • Applications can catch scheduling events to monitor or control job/trigger behavior by implementing one or more listener interfaces.
  • The Plug-In mechanism can be used add functionality to Quartz, such keeping a history of job executions, or loading job and trigger definitions from a file.
  • Quartz ships with a number of "factory built" plug-ins and listeners.
+ + + diff --git a/feed.atom b/feed.atom new file mode 100644 index 000000000..011cea69d --- /dev/null +++ b/feed.atom @@ -0,0 +1,177 @@ + + + https://www.quartz-scheduler.net + Quartz.NET + 2022-03-03T21:50:33.793Z + https://github.com/webmasterish/vuepress-plugin-feed + + + Open-source scheduling framework for .NET. + + <![CDATA[Quartz.NET 2.0 Released]]> + https://www.quartz-scheduler.net/2012/04/09/quartznet-2-0-released/ + + + 2012-04-09T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.0.1 Released]]> + https://www.quartz-scheduler.net/2012/04/22/quartznet-2-0-1-released/ + + + 2012-04-22T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.1 Released]]> + https://www.quartz-scheduler.net/2012/12/31/quartznet-2-1-released/ + + + 2012-12-31T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.1.1 Released]]> + https://www.quartz-scheduler.net/2013/01/05/quartznet-2-1-1-released/ + + + 2013-01-05T00:00:00.000Z + + + <![CDATA[Quartz.NET 2.1.2 Released]]> + https://www.quartz-scheduler.net/2013/01/13/quartznet-2-1-2-released/ + + + 2013-01-13T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.2 Released]]> + https://www.quartz-scheduler.net/2013/10/09/quartznet-2-2-released/ + + + 2013-10-09T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.2.1 Released]]> + https://www.quartz-scheduler.net/2013/11/24/quartznet-2-2-1-released/ + + + 2013-11-24T00:00:00.000Z + + + + <![CDATA[Website has moved to using GitHub pages]]> + https://www.quartz-scheduler.net/2014/01/06/website-moved-gihub-pages/ + + + 2014-01-06T00:00:00.000Z + + + <![CDATA[The tutorial has been updated to include 2.x API changes]]> + https://www.quartz-scheduler.net/2014/01/07/tutorial-updated-with-2-x-api-changes/ + + + 2014-01-07T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.2.2 Released]]> + https://www.quartz-scheduler.net/2014/02/09/quartznet-2-2-2-released/ + + + 2014-02-09T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.2.3 Released]]> + https://www.quartz-scheduler.net/2014/03/30/quartznet-2-2-3-released/ + + + 2014-03-30T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.2.4 Released]]> + https://www.quartz-scheduler.net/2014/07/27/quartznet-2-2-4-released/ + + + 2014-07-27T00:00:00.000Z + + + <![CDATA[Quartz.NET 2.3 Released]]> + https://www.quartz-scheduler.net/2014/11/08/quartznet-2-3-released/ + + + 2014-11-08T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.3.1 Released]]> + https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-1-released/ + + + 2015-01-15T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.3.2 Released]]> + https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-2-released/ + + + 2015-01-15T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.3.3 Released]]> + https://www.quartz-scheduler.net/2015/07/09/quartznet-2-3-3-released/ + + + 2015-07-09T00:00:00.000Z + + + <![CDATA[Quartz.NET 3.0 Alpha 1 Released]]> + https://www.quartz-scheduler.net/2016/08/16/quartznet-3-0-alpha1-released/ + + + 2016-08-16T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.4 Released]]> + https://www.quartz-scheduler.net/2016/08/18/quartznet-2-4-released/ + + + 2016-08-18T00:00:00.000Z + + + + <![CDATA[Quartz.NET 2.4.1 Released]]> + https://www.quartz-scheduler.net/2016/08/24/quartznet-2-4-1-released/ + + + 2016-08-24T00:00:00.000Z + + + <![CDATA[Quartz.NET 3.0 Alpha 2 Released]]> + https://www.quartz-scheduler.net/2016/08/24/quartznet-3-0-alpha2-released/ + + + 2016-08-24T00:00:00.000Z + + + \ No newline at end of file diff --git a/feed.json b/feed.json new file mode 100644 index 000000000..ebb1b9fb0 --- /dev/null +++ b/feed.json @@ -0,0 +1,144 @@ +{ + "version": "https://jsonfeed.org/version/1", + "title": "Quartz.NET", + "home_page_url": "https://www.quartz-scheduler.net", + "feed_url": "https://www.quartz-scheduler.net/feed.json", + "description": "Open-source scheduling framework for .NET.", + "items": [ + { + "id": "https://www.quartz-scheduler.net/2012/04/09/quartznet-2-0-released/", + "url": "https://www.quartz-scheduler.net/2012/04/09/quartznet-2-0-released/", + "title": "Quartz.NET 2.0 Released", + "summary": "Quartz.NET 2.0 has finally been released. Quartz.NET 2.0 introduces a new more interfaced based model of operating with the API, lots of performance improvements and bug fixes to issues found in 1.0.x line.", + "date_modified": "2012-04-09T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2012/04/22/quartznet-2-0-1-released/", + "url": "https://www.quartz-scheduler.net/2012/04/22/quartznet-2-0-1-released/", + "title": "Quartz.NET 2.0.1 Released", + "summary": "ObjectUtils.SetPropertyValue fails with explicitly implemented interface members", + "date_modified": "2012-04-22T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2012/12/31/quartznet-2-1-released/", + "url": "https://www.quartz-scheduler.net/2012/12/31/quartznet-2-1-released/", + "title": "Quartz.NET 2.1 Released", + "summary": "NthIncludedDayTrigger was removed as it was accidentally left behind even though being legacy and replaced by DailyTimeIntervalTrigger.", + "date_modified": "2012-12-31T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2013/01/05/quartznet-2-1-1-released/", + "url": "https://www.quartz-scheduler.net/2013/01/05/quartznet-2-1-1-released/", + "title": "Quartz.NET 2.1.1 Released", + "date_modified": "2013-01-05T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2013/01/13/quartznet-2-1-2-released/", + "url": "https://www.quartz-scheduler.net/2013/01/13/quartznet-2-1-2-released/", + "title": "Quartz.NET 2.1.2 Released", + "summary": "This is a maintenance release fixing issue where .NET 4.0 DLLs required 4.5 runtime due to ilmerge missing special framework parameter.", + "date_modified": "2013-01-13T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2013/10/09/quartznet-2-2-released/", + "url": "https://www.quartz-scheduler.net/2013/10/09/quartznet-2-2-released/", + "title": "Quartz.NET 2.2 Released", + "summary": "this script adds a new column SCHEDTIME to table QRTZFIRED_TRIGGERS\nfile contains the alter command for SQL Server and other database samples in comments", + "date_modified": "2013-10-09T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2013/11/24/quartznet-2-2-1-released/", + "url": "https://www.quartz-scheduler.net/2013/11/24/quartznet-2-2-1-released/", + "title": "Quartz.NET 2.2.1 Released", + "summary": "Quarts server does not properly log possible exception when starting the service\nDailyTimeIntervalTrigger GetFireTimeAfter produces incorrect result when date is in the past\nbatchTriggerAcquisitionMaxCount acquires one trigger unless batchTriggerAcquisitionFireAheadTimeWindow is also set\nOracle ODP Managed provider should set BindByName to true for OracleCommands", + "date_modified": "2013-11-24T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2014/01/06/website-moved-gihub-pages/", + "url": "https://www.quartz-scheduler.net/2014/01/06/website-moved-gihub-pages/", + "title": "Website has moved to using GitHub pages", + "date_modified": "2014-01-06T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2014/01/07/tutorial-updated-with-2-x-api-changes/", + "url": "https://www.quartz-scheduler.net/2014/01/07/tutorial-updated-with-2-x-api-changes/", + "title": "The tutorial has been updated to include 2.x API changes", + "summary": "With the latest switch to GitHub Pages it's been a joy to create content. There tutorial has now been split\nto two separate tutorials for Quartz.NET 1.x and 2.x respectively.", + "date_modified": "2014-01-07T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2014/02/09/quartznet-2-2-2-released/", + "url": "https://www.quartz-scheduler.net/2014/02/09/quartznet-2-2-2-released/", + "title": "Quartz.NET 2.2.2 Released", + "summary": "Make SQL Server table create script Azure SQL compliant\nAdd missing clustered index for QRTZBLOBTRIGGERS table\n** You need to manually add this to existing installation (tables created with old script), see ALTER TABLE [dbo].QRTZBLOBTRIGGERS WITH NOCHECK ADD... in script", + "date_modified": "2014-02-09T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2014/03/30/quartznet-2-2-3-released/", + "url": "https://www.quartz-scheduler.net/2014/03/30/quartznet-2-2-3-released/", + "title": "Quartz.NET 2.2.3 Released", + "summary": "NEW FEATURES", + "date_modified": "2014-03-30T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2014/07/27/quartznet-2-2-4-released/", + "url": "https://www.quartz-scheduler.net/2014/07/27/quartznet-2-2-4-released/", + "title": "Quartz.NET 2.2.4 Released", + "date_modified": "2014-07-27T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2014/11/08/quartznet-2-3-released/", + "url": "https://www.quartz-scheduler.net/2014/11/08/quartznet-2-3-released/", + "title": "Quartz.NET 2.3 Released", + "summary": "This is a bug fix release with some changes that warrant a minor version increment.", + "date_modified": "2014-11-08T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-1-released/", + "url": "https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-1-released/", + "title": "Quartz.NET 2.3.1 Released", + "summary": "under .NET 4.0 should now be finally fixed.", + "date_modified": "2015-01-15T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-2-released/", + "url": "https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-2-released/", + "title": "Quartz.NET 2.3.2 Released", + "summary": "CalendarIntervalTrigger and DailyTimeIntervalTrigger produce incorrect schedule builders\nIncorrect multiplication factor in DailyTimeIntervalScheduleBuilder.EndingDailyAfterCount()\nAnnualCalendar SetDayExcluded does not update internal data structures if base calendar excludes date\nEnsure IDriverDelegate members in StdAdoDelegate are virtual\nSeveral XML documentation spelling error fixes", + "date_modified": "2015-01-15T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2015/07/09/quartznet-2-3-3-released/", + "url": "https://www.quartz-scheduler.net/2015/07/09/quartznet-2-3-3-released/", + "title": "Quartz.NET 2.3.3 Released", + "date_modified": "2015-07-09T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2016/08/16/quartznet-3-0-alpha1-released/", + "url": "https://www.quartz-scheduler.net/2016/08/16/quartznet-3-0-alpha1-released/", + "title": "Quartz.NET 3.0 Alpha 1 Released", + "summary": "This is the first alpha release from the long-awaited v3 branch. This is a big overhaul (and still in progress). Internals are being modernized whilst still trying to keep sane upgrade path.", + "date_modified": "2016-08-16T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2016/08/18/quartznet-2-4-released/", + "url": "https://www.quartz-scheduler.net/2016/08/18/quartznet-2-4-released/", + "title": "Quartz.NET 2.4 Released", + "summary": "NEW FEATURE", + "date_modified": "2016-08-18T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2016/08/24/quartznet-2-4-1-released/", + "url": "https://www.quartz-scheduler.net/2016/08/24/quartznet-2-4-1-released/", + "title": "Quartz.NET 2.4.1 Released", + "date_modified": "2016-08-24T00:00:00.000Z" + }, + { + "id": "https://www.quartz-scheduler.net/2016/08/24/quartznet-3-0-alpha2-released/", + "url": "https://www.quartz-scheduler.net/2016/08/24/quartznet-3-0-alpha2-released/", + "title": "Quartz.NET 3.0 Alpha 2 Released", + "summary": "This is the second alpha of v3. This release fixes problems with schedule signaling when AdoJobStore is in use.\nThis release removes the last bits of Quartz's usage of thread local storage and thus makes async-based operations a lot safer.", + "date_modified": "2016-08-24T00:00:00.000Z" + } + ] +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..d0c25518d --- /dev/null +++ b/index.html @@ -0,0 +1,61 @@ + + + + + + Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
hero

+ Open-source job scheduling system for .NET +

+ Get Started → +

Runtime Environments

Can run embedded within an application or even instantiated as a cluster of stand-alone programs (with load-balance and fail-over capabilities)

Job Scheduling

Jobs are scheduled to run when a given trigger occurs, triggers support wide variety of scheduling options

Job Execution

Jobs can be any .NET class that implements the simple IJob interface, leaving infinite possibilities for the work jobs can perform

Job Persistence

Job stores can be implemented to provide various mechanisms for the storage of jobs, in-memory and multiple relational databases come supported out of the box

Clustering

Built-in support for load balancing your work and graceful fail-over

Listeners & Plug-Ins

Applications can catch scheduling events to monitor or control job/trigger behavior by implementing one or more listener interfaces.

Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems.

# Latest News

+ + + diff --git a/license.html b/license.html new file mode 100644 index 000000000..39baed9f5 --- /dev/null +++ b/license.html @@ -0,0 +1,61 @@ + + + + + + License | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mailing-list.html b/mailing-list.html new file mode 100644 index 000000000..6e5257554 --- /dev/null +++ b/mailing-list.html @@ -0,0 +1,56 @@ + + + + + + Mailing List | Quartz.NET + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mailing_list.html b/mailing_list.html new file mode 100644 index 000000000..00f657f3f --- /dev/null +++ b/mailing_list.html @@ -0,0 +1,31 @@ + + + + + + Mailing List | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 000000000..013d4a6a5 --- /dev/null +++ b/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "App", + "icons": [ + { + "src": "\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} \ No newline at end of file diff --git a/migration_guide.html b/migration_guide.html new file mode 100644 index 000000000..d4d54900b --- /dev/null +++ b/migration_guide.html @@ -0,0 +1,31 @@ + + + + + + Migration Guide | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/ms-icon-144x144.png b/ms-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..93ee8cb09a215fd8dfdf0976d4672dc5abd35651 GIT binary patch literal 19676 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 FzX9@)T8{t# literal 0 HcmV?d00001 diff --git a/ms-icon-150x150.png b/ms-icon-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..e3713031b39dd82db56eeba6677f861112ddafe2 GIT binary patch literal 20917 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 literal 0 HcmV?d00001 diff --git a/ms-icon-70x70.png b/ms-icon-70x70.png new file mode 100644 index 0000000000000000000000000000000000000000..1531ecbd8e5c6acaad5f167544c972873c9144d4 GIT binary patch literal 7104 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 CtRhkX literal 0 HcmV?d00001 diff --git a/quartz-logo-large.png b/quartz-logo-large.png new file mode 100644 index 0000000000000000000000000000000000000000..371fc4325137fa5d442fa829aeebe16b15c4b3c1 GIT binary patch literal 32999 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�=x&;tp*rBCxz3X=b{FSC)SK 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 literal 0 HcmV?d00001 diff --git a/rss.xml b/rss.xml new file mode 100644 index 000000000..4da758957 --- /dev/null +++ b/rss.xml @@ -0,0 +1,159 @@ + + + + Quartz.NET + https://www.quartz-scheduler.net + Open-source scheduling framework for .NET. + Thu, 03 Mar 2022 21:50:33 GMT + http://blogs.law.harvard.edu/tech/rss + https://github.com/webmasterish/vuepress-plugin-feed + + + <![CDATA[Quartz.NET 2.0 Released]]> + https://www.quartz-scheduler.net/2012/04/09/quartznet-2-0-released/ + https://www.quartz-scheduler.net/2012/04/09/quartznet-2-0-released/ + Mon, 09 Apr 2012 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.0.1 Released]]> + https://www.quartz-scheduler.net/2012/04/22/quartznet-2-0-1-released/ + https://www.quartz-scheduler.net/2012/04/22/quartznet-2-0-1-released/ + Sun, 22 Apr 2012 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.1 Released]]> + https://www.quartz-scheduler.net/2012/12/31/quartznet-2-1-released/ + https://www.quartz-scheduler.net/2012/12/31/quartznet-2-1-released/ + Mon, 31 Dec 2012 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.1.1 Released]]> + https://www.quartz-scheduler.net/2013/01/05/quartznet-2-1-1-released/ + https://www.quartz-scheduler.net/2013/01/05/quartznet-2-1-1-released/ + Sat, 05 Jan 2013 00:00:00 GMT + + + <![CDATA[Quartz.NET 2.1.2 Released]]> + https://www.quartz-scheduler.net/2013/01/13/quartznet-2-1-2-released/ + https://www.quartz-scheduler.net/2013/01/13/quartznet-2-1-2-released/ + Sun, 13 Jan 2013 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.2 Released]]> + https://www.quartz-scheduler.net/2013/10/09/quartznet-2-2-released/ + https://www.quartz-scheduler.net/2013/10/09/quartznet-2-2-released/ + Wed, 09 Oct 2013 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.2.1 Released]]> + https://www.quartz-scheduler.net/2013/11/24/quartznet-2-2-1-released/ + https://www.quartz-scheduler.net/2013/11/24/quartznet-2-2-1-released/ + Sun, 24 Nov 2013 00:00:00 GMT + + + + <![CDATA[Website has moved to using GitHub pages]]> + https://www.quartz-scheduler.net/2014/01/06/website-moved-gihub-pages/ + https://www.quartz-scheduler.net/2014/01/06/website-moved-gihub-pages/ + Mon, 06 Jan 2014 00:00:00 GMT + + + <![CDATA[The tutorial has been updated to include 2.x API changes]]> + https://www.quartz-scheduler.net/2014/01/07/tutorial-updated-with-2-x-api-changes/ + https://www.quartz-scheduler.net/2014/01/07/tutorial-updated-with-2-x-api-changes/ + Tue, 07 Jan 2014 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.2.2 Released]]> + https://www.quartz-scheduler.net/2014/02/09/quartznet-2-2-2-released/ + https://www.quartz-scheduler.net/2014/02/09/quartznet-2-2-2-released/ + Sun, 09 Feb 2014 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.2.3 Released]]> + https://www.quartz-scheduler.net/2014/03/30/quartznet-2-2-3-released/ + https://www.quartz-scheduler.net/2014/03/30/quartznet-2-2-3-released/ + Sun, 30 Mar 2014 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.2.4 Released]]> + https://www.quartz-scheduler.net/2014/07/27/quartznet-2-2-4-released/ + https://www.quartz-scheduler.net/2014/07/27/quartznet-2-2-4-released/ + Sun, 27 Jul 2014 00:00:00 GMT + + + <![CDATA[Quartz.NET 2.3 Released]]> + https://www.quartz-scheduler.net/2014/11/08/quartznet-2-3-released/ + https://www.quartz-scheduler.net/2014/11/08/quartznet-2-3-released/ + Sat, 08 Nov 2014 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.3.1 Released]]> + https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-1-released/ + https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-1-released/ + Thu, 15 Jan 2015 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.3.2 Released]]> + https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-2-released/ + https://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-2-released/ + Thu, 15 Jan 2015 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.3.3 Released]]> + https://www.quartz-scheduler.net/2015/07/09/quartznet-2-3-3-released/ + https://www.quartz-scheduler.net/2015/07/09/quartznet-2-3-3-released/ + Thu, 09 Jul 2015 00:00:00 GMT + + + <![CDATA[Quartz.NET 3.0 Alpha 1 Released]]> + https://www.quartz-scheduler.net/2016/08/16/quartznet-3-0-alpha1-released/ + https://www.quartz-scheduler.net/2016/08/16/quartznet-3-0-alpha1-released/ + Tue, 16 Aug 2016 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.4 Released]]> + https://www.quartz-scheduler.net/2016/08/18/quartznet-2-4-released/ + https://www.quartz-scheduler.net/2016/08/18/quartznet-2-4-released/ + Thu, 18 Aug 2016 00:00:00 GMT + + + + <![CDATA[Quartz.NET 2.4.1 Released]]> + https://www.quartz-scheduler.net/2016/08/24/quartznet-2-4-1-released/ + https://www.quartz-scheduler.net/2016/08/24/quartznet-2-4-1-released/ + Wed, 24 Aug 2016 00:00:00 GMT + + + <![CDATA[Quartz.NET 3.0 Alpha 2 Released]]> + https://www.quartz-scheduler.net/2016/08/24/quartznet-3-0-alpha2-released/ + https://www.quartz-scheduler.net/2016/08/24/quartznet-3-0-alpha2-released/ + Wed, 24 Aug 2016 00:00:00 GMT + + + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000..4829a02ad --- /dev/null +++ b/sitemap.xml @@ -0,0 +1 @@ +https://www.quartz-scheduler.net/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2012/04/09/quartznet-2-0-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2012/04/22/quartznet-2-0-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2012/12/31/quartznet-2-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2013/01/05/quartznet-2-1-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2013/01/13/quartznet-2-1-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2013/10/09/quartznet-2-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2013/11/24/quartznet-2-2-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2014/01/06/website-moved-gihub-pages/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2014/01/07/tutorial-updated-with-2-x-api-changes/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2014/02/09/quartznet-2-2-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2014/03/30/quartznet-2-2-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2014/07/27/quartznet-2-2-4-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2014/11/08/quartznet-2-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2015/01/15/quartznet-2-3-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2015/07/09/quartznet-2-3-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2016/08/16/quartznet-3-0-alpha1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2016/08/18/quartznet-2-4-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2016/08/24/quartznet-2-4-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2016/08/24/quartznet-3-0-alpha2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2017/02/18/quartznet-2-5-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2017/07/30/quartznet-2-6-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2017/07/30/quartznet-3-0-alpha3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2017/10/08/quartznet-3-0-beta1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2017/10/09/quartznet-2-6-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2017/12/30/quartznet-3-0-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/01/21/quartznet-3-0-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/01/25/quartznet-3-0-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/02/24/quartznet-3-0-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/03/04/quartznet-3-0-4-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/05/27/quartznet-2-6-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/05/27/quartznet-3-0-5-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/07/06/quartznet-3-0-6-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2018/10/07/quartznet-3-0-7-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/07/06/website-refresh/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/07/08/quartznet-3-1-beta-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/07/14/quartznet-3-1-beta-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/07/21/quartznet-3-1-beta-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/07/21/quartznet-3-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/07/24/quartznet-3-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/10/01/quartznet-3-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/10/18/quartznet-3-2-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/10/19/quartznet-3-2-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2020/10/31/quartznet-3-2-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2021/01/19/quartznet-3-2-4-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2021/04/07/quartznet-3-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2021/04/08/quartznet-3-3-1-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2021/04/09/quartznet-3-3-2-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/2021/08/01/quartznet-3-3-3-released/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/blog.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/best-practices.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/faq.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/advanced-enterprise-features.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/configuration-resource-usage-and-scheduler-factory.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/crontriggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/job-stores.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/jobs-and-triggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/miscellaneous-features.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/more-about-jobs.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/more-about-triggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/scheduler-listeners.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/simpletriggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/trigger-and-job-listeners.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-1.x/tutorial/using-quartz.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/configuration/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/migration-guide.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/advanced-enterprise-features.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/configuration-resource-usage-and-scheduler-factory.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/crontrigger.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/crontriggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/job-stores.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/jobs-and-triggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/miscellaneous-features.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/more-about-jobs.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/more-about-triggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/scheduler-listeners.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/simpletriggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/trigger-and-job-listeners.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/using-quartz.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/configuration/reference.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/migration-guide.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/aspnet-core-integration.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/hosted-services-integration.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/json-serialization.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/microsoft-di-integration.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/opentelemetry-integration.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/opentracing-integration.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/quartz-jobs.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/quartz-plugins.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/packages/timezoneconverter-integration.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/advanced-enterprise-features.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/configuration-resource-usage-and-scheduler-factory.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/crontrigger.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/crontriggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/job-stores.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/jobs-and-triggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/miscellaneous-features.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/more-about-jobs.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/more-about-triggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/using-quartz.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/download.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/faq.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/features.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/license.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/mailing-list.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/mailing_list.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/migration_guide.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_1.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_10.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_11.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_12.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_2.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_3.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_4.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_5.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_6.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_7.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_8.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/tutorial/lesson_9.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/trigger-and-job-listeners.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/simpletriggers.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/scheduler-listeners.html2022-03-03T21:49:06.000Zdailyhttps://www.quartz-scheduler.net/blogdailyhttps://www.quartz-scheduler.net/blogpage/2/dailyhttps://www.quartz-scheduler.net/blogpage/3/dailyhttps://www.quartz-scheduler.net/blogpage/4/dailyhttps://www.quartz-scheduler.net/blogpage/5/daily \ No newline at end of file diff --git a/tutorial/index.html b/tutorial/index.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/index.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +

+ + + diff --git a/tutorial/lesson_1.html b/tutorial/lesson_1.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_1.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_10.html b/tutorial/lesson_10.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_10.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_11.html b/tutorial/lesson_11.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_11.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_12.html b/tutorial/lesson_12.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_12.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_2.html b/tutorial/lesson_2.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_2.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_3.html b/tutorial/lesson_3.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_3.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_4.html b/tutorial/lesson_4.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_4.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_5.html b/tutorial/lesson_5.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_5.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_6.html b/tutorial/lesson_6.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_6.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_7.html b/tutorial/lesson_7.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_7.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_8.html b/tutorial/lesson_8.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_8.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/tutorial/lesson_9.html b/tutorial/lesson_9.html new file mode 100644 index 000000000..3a46dbbcd --- /dev/null +++ b/tutorial/lesson_9.html @@ -0,0 +1,31 @@ + + + + + + JobStores | Quartz.NET + + + + + + + + + + + + + + + + + + + + + +
+ + + From 4b64a7f2483b41048f4ac9546f7d785feccddcb2 Mon Sep 17 00:00:00 2001 From: Roel <60602417+RoelStierum@users.noreply.github.com> Date: Mon, 14 Mar 2022 11:44:18 +0100 Subject: [PATCH 2/2] Update copyright Copyright was outdated. Updated from 2020 to 2022 --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index d0c25518d..151af7b73 100644 --- a/index.html +++ b/index.html @@ -54,7 +54,7 @@

Get Started →

Runtime Environments

Can run embedded within an application or even instantiated as a cluster of stand-alone programs (with load-balance and fail-over capabilities)

Job Scheduling

Jobs are scheduled to run when a given trigger occurs, triggers support wide variety of scheduling options

Job Execution

Jobs can be any .NET class that implements the simple IJob interface, leaving infinite possibilities for the work jobs can perform

Job Persistence

Job stores can be implemented to provide various mechanisms for the storage of jobs, in-memory and multiple relational databases come supported out of the box

Clustering

Built-in support for load balancing your work and graceful fail-over

Listeners & Plug-Ins

Applications can catch scheduling events to monitor or control job/trigger behavior by implementing one or more listener interfaces.

Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems.

# Latest News