You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aurora.apache.org by ke...@apache.org on 2014/04/24 03:18:17 UTC
[1/5] Revert "AURORA-132: Cron system based on Quartz"
Repository: incubator-aurora
Updated Branches:
refs/heads/master 53dc494ff -> 5de2b1ab3
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/resources/org/apache/aurora/scheduler/cron/expected-predictions.json
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/aurora/scheduler/cron/expected-predictions.json b/src/test/resources/org/apache/aurora/scheduler/cron/expected-predictions.json
deleted file mode 100644
index dced8b4..0000000
--- a/src/test/resources/org/apache/aurora/scheduler/cron/expected-predictions.json
+++ /dev/null
@@ -1,3332 +0,0 @@
-[
- {
- "schedule": "0 20 * * 1",
- "triggerTimes": [
- 417600000,
- 1022400000,
- 1627200000,
- 2232000000,
- 2836800000,
- 3441600000,
- 4046400000,
- 4651200000,
- 5256000000,
- 5860800000
- ]
- },
- {
- "schedule": "11 * * * *",
- "triggerTimes": [
- 660000,
- 4260000,
- 7860000,
- 11460000,
- 15060000,
- 18660000,
- 22260000,
- 25860000,
- 29460000,
- 33060000
- ]
- },
- {
- "schedule": "04 02 * * *",
- "triggerTimes": [
- 7440000,
- 93840000,
- 180240000,
- 266640000,
- 353040000,
- 439440000,
- 525840000,
- 612240000,
- 698640000,
- 785040000
- ]
- },
- {
- "schedule": "09 22 * * *",
- "triggerTimes": [
- 79740000,
- 166140000,
- 252540000,
- 338940000,
- 425340000,
- 511740000,
- 598140000,
- 684540000,
- 770940000,
- 857340000
- ]
- },
- {
- "schedule": "1-56/5 * * * *",
- "triggerTimes": [
- 60000,
- 360000,
- 660000,
- 960000,
- 1260000,
- 1560000,
- 1860000,
- 2160000,
- 2460000,
- 2760000
- ]
- },
- {
- "schedule": "05 02,08,12 * * *",
- "triggerTimes": [
- 7500000,
- 29100000,
- 43500000,
- 93900000,
- 115500000,
- 129900000,
- 180300000,
- 201900000,
- 216300000,
- 266700000
- ]
- },
- {
- "schedule": "26 * * * *",
- "triggerTimes": [
- 1560000,
- 5160000,
- 8760000,
- 12360000,
- 15960000,
- 19560000,
- 23160000,
- 26760000,
- 30360000,
- 33960000
- ]
- },
- {
- "schedule": "3,43 * * * *",
- "triggerTimes": [
- 180000,
- 2580000,
- 3780000,
- 6180000,
- 7380000,
- 9780000,
- 10980000,
- 13380000,
- 14580000,
- 16980000
- ]
- },
- {
- "schedule": "0 17-23 * * 1-5",
- "triggerTimes": [
- 61200000,
- 64800000,
- 68400000,
- 72000000,
- 75600000,
- 79200000,
- 82800000,
- 147600000,
- 151200000,
- 154800000
- ]
- },
- {
- "schedule": "0 0,12 * * *",
- "triggerTimes": [
- 43200000,
- 86400000,
- 129600000,
- 172800000,
- 216000000,
- 259200000,
- 302400000,
- 345600000,
- 388800000,
- 432000000
- ]
- },
- {
- "schedule": "10 02,08,12 * * *",
- "triggerTimes": [
- 7800000,
- 29400000,
- 43800000,
- 94200000,
- 115800000,
- 130200000,
- 180600000,
- 202200000,
- 216600000,
- 267000000
- ]
- },
- {
- "schedule": "50 */4 * * *",
- "triggerTimes": [
- 3000000,
- 17400000,
- 31800000,
- 46200000,
- 60600000,
- 75000000,
- 89400000,
- 103800000,
- 118200000,
- 132600000
- ]
- },
- {
- "schedule": "10 02,08,14,20 * * *",
- "triggerTimes": [
- 7800000,
- 29400000,
- 51000000,
- 72600000,
- 94200000,
- 115800000,
- 137400000,
- 159000000,
- 180600000,
- 202200000
- ]
- },
- {
- "schedule": "0 */6 * * *",
- "triggerTimes": [
- 21600000,
- 43200000,
- 64800000,
- 86400000,
- 108000000,
- 129600000,
- 151200000,
- 172800000,
- 194400000,
- 216000000
- ]
- },
- {
- "schedule": "* * * * *",
- "triggerTimes": [
- 60000,
- 120000,
- 180000,
- 240000,
- 300000,
- 360000,
- 420000,
- 480000,
- 540000,
- 600000
- ]
- },
- {
- "schedule": "30 15 * * *,",
- "triggerTimes": [
- 55800000,
- 142200000,
- 228600000,
- 315000000,
- 401400000,
- 487800000,
- 574200000,
- 660600000,
- 747000000,
- 833400000
- ]
- },
- {
- "schedule": "00 11 * * *",
- "triggerTimes": [
- 39600000,
- 126000000,
- 212400000,
- 298800000,
- 385200000,
- 471600000,
- 558000000,
- 644400000,
- 730800000,
- 817200000
- ]
- },
- {
- "schedule": "55 06 * * *",
- "triggerTimes": [
- 24900000,
- 111300000,
- 197700000,
- 284100000,
- 370500000,
- 456900000,
- 543300000,
- 629700000,
- 716100000,
- 802500000
- ]
- },
- {
- "schedule": "0 4 * * *",
- "triggerTimes": [
- 14400000,
- 100800000,
- 187200000,
- 273600000,
- 360000000,
- 446400000,
- 532800000,
- 619200000,
- 705600000,
- 792000000
- ]
- },
- {
- "schedule": "55 */1 * * *",
- "triggerTimes": [
- 3300000,
- 6900000,
- 10500000,
- 14100000,
- 17700000,
- 21300000,
- 24900000,
- 28500000,
- 32100000,
- 35700000
- ]
- },
- {
- "schedule": "15 */3 * * *",
- "triggerTimes": [
- 900000,
- 11700000,
- 22500000,
- 33300000,
- 44100000,
- 54900000,
- 65700000,
- 76500000,
- 87300000,
- 98100000
- ]
- },
- {
- "schedule": "42 8,12,16 * * *",
- "triggerTimes": [
- 31320000,
- 45720000,
- 60120000,
- 117720000,
- 132120000,
- 146520000,
- 204120000,
- 218520000,
- 232920000,
- 290520000
- ]
- },
- {
- "schedule": "23 * * * *",
- "triggerTimes": [
- 1380000,
- 4980000,
- 8580000,
- 12180000,
- 15780000,
- 19380000,
- 22980000,
- 26580000,
- 30180000,
- 33780000
- ]
- },
- {
- "schedule": "10 16 * * *",
- "triggerTimes": [
- 58200000,
- 144600000,
- 231000000,
- 317400000,
- 403800000,
- 490200000,
- 576600000,
- 663000000,
- 749400000,
- 835800000
- ]
- },
- {
- "schedule": "*/30 * * * *",
- "triggerTimes": [
- 1800000,
- 3600000,
- 5400000,
- 7200000,
- 9000000,
- 10800000,
- 12600000,
- 14400000,
- 16200000,
- 18000000
- ]
- },
- {
- "schedule": "20 */3 * * *",
- "triggerTimes": [
- 1200000,
- 12000000,
- 22800000,
- 33600000,
- 44400000,
- 55200000,
- 66000000,
- 76800000,
- 87600000,
- 98400000
- ]
- },
- {
- "schedule": "8 6,12,18 * * *",
- "triggerTimes": [
- 22080000,
- 43680000,
- 65280000,
- 108480000,
- 130080000,
- 151680000,
- 194880000,
- 216480000,
- 238080000,
- 281280000
- ]
- },
- {
- "schedule": "30 7,12,22 * * *",
- "triggerTimes": [
- 27000000,
- 45000000,
- 81000000,
- 113400000,
- 131400000,
- 167400000,
- 199800000,
- 217800000,
- 253800000,
- 286200000
- ]
- },
- {
- "schedule": "0 0 12 * *",
- "triggerTimes": [
- 950400000,
- 3628800000,
- 6048000000,
- 8726400000,
- 11318400000,
- 13996800000,
- 16588800000,
- 19267200000,
- 21945600000,
- 24537600000
- ]
- },
- {
- "schedule": "17 5,8,13,16,19 * * *",
- "triggerTimes": [
- 19020000,
- 29820000,
- 47820000,
- 58620000,
- 69420000,
- 105420000,
- 116220000,
- 134220000,
- 145020000,
- 155820000
- ]
- },
- {
- "schedule": "27 8,20 * * *",
- "triggerTimes": [
- 30420000,
- 73620000,
- 116820000,
- 160020000,
- 203220000,
- 246420000,
- 289620000,
- 332820000,
- 376020000,
- 419220000
- ]
- },
- {
- "schedule": "15 */6 * * *",
- "triggerTimes": [
- 900000,
- 22500000,
- 44100000,
- 65700000,
- 87300000,
- 108900000,
- 130500000,
- 152100000,
- 173700000,
- 195300000
- ]
- },
- {
- "schedule": "01 15 * * *",
- "triggerTimes": [
- 54060000,
- 140460000,
- 226860000,
- 313260000,
- 399660000,
- 486060000,
- 572460000,
- 658860000,
- 745260000,
- 831660000
- ]
- },
- {
- "schedule": "0 18 * * *",
- "triggerTimes": [
- 64800000,
- 151200000,
- 237600000,
- 324000000,
- 410400000,
- 496800000,
- 583200000,
- 669600000,
- 756000000,
- 842400000
- ]
- },
- {
- "schedule": "24 * * * *",
- "triggerTimes": [
- 1440000,
- 5040000,
- 8640000,
- 12240000,
- 15840000,
- 19440000,
- 23040000,
- 26640000,
- 30240000,
- 33840000
- ]
- },
- {
- "schedule": "18 00 * * *",
- "triggerTimes": [
- 1080000,
- 87480000,
- 173880000,
- 260280000,
- 346680000,
- 433080000,
- 519480000,
- 605880000,
- 692280000,
- 778680000
- ]
- },
- {
- "schedule": "0 16 * * *",
- "triggerTimes": [
- 57600000,
- 144000000,
- 230400000,
- 316800000,
- 403200000,
- 489600000,
- 576000000,
- 662400000,
- 748800000,
- 835200000
- ]
- },
- {
- "schedule": "45 5 * * *",
- "triggerTimes": [
- 20700000,
- 107100000,
- 193500000,
- 279900000,
- 366300000,
- 452700000,
- 539100000,
- 625500000,
- 711900000,
- 798300000
- ]
- },
- {
- "schedule": "0 18 * * 4",
- "triggerTimes": [
- 64800000,
- 669600000,
- 1274400000,
- 1879200000,
- 2484000000,
- 3088800000,
- 3693600000,
- 4298400000,
- 4903200000,
- 5508000000
- ]
- },
- {
- "schedule": "30 19 * * *",
- "triggerTimes": [
- 70200000,
- 156600000,
- 243000000,
- 329400000,
- 415800000,
- 502200000,
- 588600000,
- 675000000,
- 761400000,
- 847800000
- ]
- },
- {
- "schedule": "0 13 * * 2",
- "triggerTimes": [
- 478800000,
- 1083600000,
- 1688400000,
- 2293200000,
- 2898000000,
- 3502800000,
- 4107600000,
- 4712400000,
- 5317200000,
- 5922000000
- ]
- },
- {
- "schedule": "25 17,20,21,23 * * *",
- "triggerTimes": [
- 62700000,
- 73500000,
- 77100000,
- 84300000,
- 149100000,
- 159900000,
- 163500000,
- 170700000,
- 235500000,
- 246300000
- ]
- },
- {
- "schedule": "0 13 * * 3",
- "triggerTimes": [
- 565200000,
- 1170000000,
- 1774800000,
- 2379600000,
- 2984400000,
- 3589200000,
- 4194000000,
- 4798800000,
- 5403600000,
- 6008400000
- ]
- },
- {
- "schedule": "58 */2 * * *",
- "triggerTimes": [
- 3480000,
- 10680000,
- 17880000,
- 25080000,
- 32280000,
- 39480000,
- 46680000,
- 53880000,
- 61080000,
- 68280000
- ]
- },
- {
- "schedule": "0 9 4,18 * *",
- "triggerTimes": [
- 291600000,
- 1501200000,
- 2970000000,
- 4179600000,
- 5389200000,
- 6598800000,
- 8067600000,
- 9277200000,
- 10659600000,
- 11869200000
- ]
- },
- {
- "schedule": "37 */6 * * *",
- "triggerTimes": [
- 2220000,
- 23820000,
- 45420000,
- 67020000,
- 88620000,
- 110220000,
- 131820000,
- 153420000,
- 175020000,
- 196620000
- ]
- },
- {
- "schedule": "00 14 * * *",
- "triggerTimes": [
- 50400000,
- 136800000,
- 223200000,
- 309600000,
- 396000000,
- 482400000,
- 568800000,
- 655200000,
- 741600000,
- 828000000
- ]
- },
- {
- "schedule": "0 * * * *",
- "triggerTimes": [
- 3600000,
- 7200000,
- 10800000,
- 14400000,
- 18000000,
- 21600000,
- 25200000,
- 28800000,
- 32400000,
- 36000000
- ]
- },
- {
- "schedule": "29 9,16,22 * * *",
- "triggerTimes": [
- 34140000,
- 59340000,
- 80940000,
- 120540000,
- 145740000,
- 167340000,
- 206940000,
- 232140000,
- 253740000,
- 293340000
- ]
- },
- {
- "schedule": "37 3 * * *",
- "triggerTimes": [
- 13020000,
- 99420000,
- 185820000,
- 272220000,
- 358620000,
- 445020000,
- 531420000,
- 617820000,
- 704220000,
- 790620000
- ]
- },
- {
- "schedule": "*/5 * * * *",
- "triggerTimes": [
- 300000,
- 600000,
- 900000,
- 1200000,
- 1500000,
- 1800000,
- 2100000,
- 2400000,
- 2700000,
- 3000000
- ]
- },
- {
- "schedule": "7 */2 * * *",
- "triggerTimes": [
- 420000,
- 7620000,
- 14820000,
- 22020000,
- 29220000,
- 36420000,
- 43620000,
- 50820000,
- 58020000,
- 65220000
- ]
- },
- {
- "schedule": "55 07 * * *",
- "triggerTimes": [
- 28500000,
- 114900000,
- 201300000,
- 287700000,
- 374100000,
- 460500000,
- 546900000,
- 633300000,
- 719700000,
- 806100000
- ]
- },
- {
- "schedule": "0 19 * * *",
- "triggerTimes": [
- 68400000,
- 154800000,
- 241200000,
- 327600000,
- 414000000,
- 500400000,
- 586800000,
- 673200000,
- 759600000,
- 846000000
- ]
- },
- {
- "schedule": "15 */2 * * *",
- "triggerTimes": [
- 900000,
- 8100000,
- 15300000,
- 22500000,
- 29700000,
- 36900000,
- 44100000,
- 51300000,
- 58500000,
- 65700000
- ]
- },
- {
- "schedule": "17 00 * * *",
- "triggerTimes": [
- 1020000,
- 87420000,
- 173820000,
- 260220000,
- 346620000,
- 433020000,
- 519420000,
- 605820000,
- 692220000,
- 778620000
- ]
- },
- {
- "schedule": "0 0 * * 1",
- "triggerTimes": [
- 345600000,
- 950400000,
- 1555200000,
- 2160000000,
- 2764800000,
- 3369600000,
- 3974400000,
- 4579200000,
- 5184000000,
- 5788800000
- ]
- },
- {
- "schedule": "29 */4 * * *",
- "triggerTimes": [
- 1740000,
- 16140000,
- 30540000,
- 44940000,
- 59340000,
- 73740000,
- 88140000,
- 102540000,
- 116940000,
- 131340000
- ]
- },
- {
- "schedule": "0 23 * * *",
- "triggerTimes": [
- 82800000,
- 169200000,
- 255600000,
- 342000000,
- 428400000,
- 514800000,
- 601200000,
- 687600000,
- 774000000,
- 860400000
- ]
- },
- {
- "schedule": "0 7 * * *",
- "triggerTimes": [
- 25200000,
- 111600000,
- 198000000,
- 284400000,
- 370800000,
- 457200000,
- 543600000,
- 630000000,
- 716400000,
- 802800000
- ]
- },
- {
- "schedule": "12 * * * *",
- "triggerTimes": [
- 720000,
- 4320000,
- 7920000,
- 11520000,
- 15120000,
- 18720000,
- 22320000,
- 25920000,
- 29520000,
- 33120000
- ]
- },
- {
- "schedule": "0 23 * * 3",
- "triggerTimes": [
- 601200000,
- 1206000000,
- 1810800000,
- 2415600000,
- 3020400000,
- 3625200000,
- 4230000000,
- 4834800000,
- 5439600000,
- 6044400000
- ]
- },
- {
- "schedule": "23 */4 * * *",
- "triggerTimes": [
- 1380000,
- 15780000,
- 30180000,
- 44580000,
- 58980000,
- 73380000,
- 87780000,
- 102180000,
- 116580000,
- 130980000
- ]
- },
- {
- "schedule": "30 1-23/2 * * *",
- "triggerTimes": [
- 5400000,
- 12600000,
- 19800000,
- 27000000,
- 34200000,
- 41400000,
- 48600000,
- 55800000,
- 63000000,
- 70200000
- ]
- },
- {
- "schedule": "5,15,25,35,45,55 * * * *",
- "triggerTimes": [
- 300000,
- 900000,
- 1500000,
- 2100000,
- 2700000,
- 3300000,
- 3900000,
- 4500000,
- 5100000,
- 5700000
- ]
- },
- {
- "schedule": "23 1,11,21 * * *",
- "triggerTimes": [
- 4980000,
- 40980000,
- 76980000,
- 91380000,
- 127380000,
- 163380000,
- 177780000,
- 213780000,
- 249780000,
- 264180000
- ]
- },
- {
- "schedule": "15 04,10,16,22 * * *",
- "triggerTimes": [
- 15300000,
- 36900000,
- 58500000,
- 80100000,
- 101700000,
- 123300000,
- 144900000,
- 166500000,
- 188100000,
- 209700000
- ]
- },
- {
- "schedule": "*/20 * * * *",
- "triggerTimes": [
- 1200000,
- 2400000,
- 3600000,
- 4800000,
- 6000000,
- 7200000,
- 8400000,
- 9600000,
- 10800000,
- 12000000
- ]
- },
- {
- "schedule": "12,42 * * * *",
- "triggerTimes": [
- 720000,
- 2520000,
- 4320000,
- 6120000,
- 7920000,
- 9720000,
- 11520000,
- 13320000,
- 15120000,
- 16920000
- ]
- },
- {
- "schedule": "26 2,6,10,14,18,22 * * *",
- "triggerTimes": [
- 8760000,
- 23160000,
- 37560000,
- 51960000,
- 66360000,
- 80760000,
- 95160000,
- 109560000,
- 123960000,
- 138360000
- ]
- },
- {
- "schedule": "0 3,6,9,12,15,18,21 * * *",
- "triggerTimes": [
- 10800000,
- 21600000,
- 32400000,
- 43200000,
- 54000000,
- 64800000,
- 75600000,
- 97200000,
- 108000000,
- 118800000
- ]
- },
- {
- "schedule": "25 14 * * *",
- "triggerTimes": [
- 51900000,
- 138300000,
- 224700000,
- 311100000,
- 397500000,
- 483900000,
- 570300000,
- 656700000,
- 743100000,
- 829500000
- ]
- },
- {
- "schedule": "0 5 * * *,",
- "triggerTimes": [
- 18000000,
- 104400000,
- 190800000,
- 277200000,
- 363600000,
- 450000000,
- 536400000,
- 622800000,
- 709200000,
- 795600000
- ]
- },
- {
- "schedule": "43 * * * *",
- "triggerTimes": [
- 2580000,
- 6180000,
- 9780000,
- 13380000,
- 16980000,
- 20580000,
- 24180000,
- 27780000,
- 31380000,
- 34980000
- ]
- },
- {
- "schedule": "39 6,12,16 * * *",
- "triggerTimes": [
- 23940000,
- 45540000,
- 59940000,
- 110340000,
- 131940000,
- 146340000,
- 196740000,
- 218340000,
- 232740000,
- 283140000
- ]
- },
- {
- "schedule": "0 9 1 * *",
- "triggerTimes": [
- 32400000,
- 2710800000,
- 5130000000,
- 7808400000,
- 10400400000,
- 13078800000,
- 15670800000,
- 18349200000,
- 21027600000,
- 23619600000
- ]
- },
- {
- "schedule": "14-59/30 * * * *",
- "triggerTimes": [
- 840000,
- 2640000,
- 4440000,
- 6240000,
- 8040000,
- 9840000,
- 11640000,
- 13440000,
- 15240000,
- 17040000
- ]
- },
- {
- "schedule": "0 0 * * *",
- "triggerTimes": [
- 86400000,
- 172800000,
- 259200000,
- 345600000,
- 432000000,
- 518400000,
- 604800000,
- 691200000,
- 777600000,
- 864000000
- ]
- },
- {
- "schedule": "0 */3 * * *",
- "triggerTimes": [
- 10800000,
- 21600000,
- 32400000,
- 43200000,
- 54000000,
- 64800000,
- 75600000,
- 86400000,
- 97200000,
- 108000000
- ]
- },
- {
- "schedule": "16 5,13,21 * * *",
- "triggerTimes": [
- 18960000,
- 47760000,
- 76560000,
- 105360000,
- 134160000,
- 162960000,
- 191760000,
- 220560000,
- 249360000,
- 278160000
- ]
- },
- {
- "schedule": "30 18,23 * * MON-FRI",
- "triggerTimes": [
- 66600000,
- 84600000,
- 153000000,
- 171000000,
- 412200000,
- 430200000,
- 498600000,
- 516600000,
- 585000000,
- 603000000
- ]
- },
- {
- "schedule": "0,15,30,45 * * * *",
- "triggerTimes": [
- 900000,
- 1800000,
- 2700000,
- 3600000,
- 4500000,
- 5400000,
- 6300000,
- 7200000,
- 8100000,
- 9000000
- ]
- },
- {
- "schedule": "42 8,20 * * *",
- "triggerTimes": [
- 31320000,
- 74520000,
- 117720000,
- 160920000,
- 204120000,
- 247320000,
- 290520000,
- 333720000,
- 376920000,
- 420120000
- ]
- },
- {
- "schedule": "46 */6 * * *",
- "triggerTimes": [
- 2760000,
- 24360000,
- 45960000,
- 67560000,
- 89160000,
- 110760000,
- 132360000,
- 153960000,
- 175560000,
- 197160000
- ]
- },
- {
- "schedule": "0 3 * * *",
- "triggerTimes": [
- 10800000,
- 97200000,
- 183600000,
- 270000000,
- 356400000,
- 442800000,
- 529200000,
- 615600000,
- 702000000,
- 788400000
- ]
- },
- {
- "schedule": "16 9,16 * * *",
- "triggerTimes": [
- 33360000,
- 58560000,
- 119760000,
- 144960000,
- 206160000,
- 231360000,
- 292560000,
- 317760000,
- 378960000,
- 404160000
- ]
- },
- {
- "schedule": "15 0 * * *",
- "triggerTimes": [
- 900000,
- 87300000,
- 173700000,
- 260100000,
- 346500000,
- 432900000,
- 519300000,
- 605700000,
- 692100000,
- 778500000
- ]
- },
- {
- "schedule": "05 * * * *",
- "triggerTimes": [
- 300000,
- 3900000,
- 7500000,
- 11100000,
- 14700000,
- 18300000,
- 21900000,
- 25500000,
- 29100000,
- 32700000
- ]
- },
- {
- "schedule": "30 * * * *",
- "triggerTimes": [
- 1800000,
- 5400000,
- 9000000,
- 12600000,
- 16200000,
- 19800000,
- 23400000,
- 27000000,
- 30600000,
- 34200000
- ]
- },
- {
- "schedule": "0 2,14 * * *",
- "triggerTimes": [
- 7200000,
- 50400000,
- 93600000,
- 136800000,
- 180000000,
- 223200000,
- 266400000,
- 309600000,
- 352800000,
- 396000000
- ]
- },
- {
- "schedule": "28 23 * * 3",
- "triggerTimes": [
- 602880000,
- 1207680000,
- 1812480000,
- 2417280000,
- 3022080000,
- 3626880000,
- 4231680000,
- 4836480000,
- 5441280000,
- 6046080000
- ]
- },
- {
- "schedule": "5 */4 * * *",
- "triggerTimes": [
- 300000,
- 14700000,
- 29100000,
- 43500000,
- 57900000,
- 72300000,
- 86700000,
- 101100000,
- 115500000,
- 129900000
- ]
- },
- {
- "schedule": "0 18,22 * * MON-FRI",
- "triggerTimes": [
- 64800000,
- 79200000,
- 151200000,
- 165600000,
- 410400000,
- 424800000,
- 496800000,
- 511200000,
- 583200000,
- 597600000
- ]
- },
- {
- "schedule": "01 21 * * *",
- "triggerTimes": [
- 75660000,
- 162060000,
- 248460000,
- 334860000,
- 421260000,
- 507660000,
- 594060000,
- 680460000,
- 766860000,
- 853260000
- ]
- },
- {
- "schedule": "1 */6 * * *",
- "triggerTimes": [
- 60000,
- 21660000,
- 43260000,
- 64860000,
- 86460000,
- 108060000,
- 129660000,
- 151260000,
- 172860000,
- 194460000
- ]
- },
- {
- "schedule": "*/10 * * * *",
- "triggerTimes": [
- 600000,
- 1200000,
- 1800000,
- 2400000,
- 3000000,
- 3600000,
- 4200000,
- 4800000,
- 5400000,
- 6000000
- ]
- },
- {
- "schedule": "44 */2 * * *",
- "triggerTimes": [
- 2640000,
- 9840000,
- 17040000,
- 24240000,
- 31440000,
- 38640000,
- 45840000,
- 53040000,
- 60240000,
- 67440000
- ]
- },
- {
- "schedule": "30 2 * * *",
- "triggerTimes": [
- 9000000,
- 95400000,
- 181800000,
- 268200000,
- 354600000,
- 441000000,
- 527400000,
- 613800000,
- 700200000,
- 786600000
- ]
- },
- {
- "schedule": "58 * * * *",
- "triggerTimes": [
- 3480000,
- 7080000,
- 10680000,
- 14280000,
- 17880000,
- 21480000,
- 25080000,
- 28680000,
- 32280000,
- 35880000
- ]
- },
- {
- "schedule": "30 23 * * 6",
- "triggerTimes": [
- 257400000,
- 862200000,
- 1467000000,
- 2071800000,
- 2676600000,
- 3281400000,
- 3886200000,
- 4491000000,
- 5095800000,
- 5700600000
- ]
- },
- {
- "schedule": "40 23 * * *",
- "triggerTimes": [
- 85200000,
- 171600000,
- 258000000,
- 344400000,
- 430800000,
- 517200000,
- 603600000,
- 690000000,
- 776400000,
- 862800000
- ]
- },
- {
- "schedule": "0 5,10,15,20,1 * * *",
- "triggerTimes": [
- 3600000,
- 18000000,
- 36000000,
- 54000000,
- 72000000,
- 90000000,
- 104400000,
- 122400000,
- 140400000,
- 158400000
- ]
- },
- {
- "schedule": "22 * * * *",
- "triggerTimes": [
- 1320000,
- 4920000,
- 8520000,
- 12120000,
- 15720000,
- 19320000,
- 22920000,
- 26520000,
- 30120000,
- 33720000
- ]
- },
- {
- "schedule": "00 17 1-3,5-31 * *",
- "triggerTimes": [
- 61200000,
- 147600000,
- 234000000,
- 406800000,
- 493200000,
- 579600000,
- 666000000,
- 752400000,
- 838800000,
- 925200000
- ]
- },
- {
- "schedule": "0 2 1 * *",
- "triggerTimes": [
- 7200000,
- 2685600000,
- 5104800000,
- 7783200000,
- 10375200000,
- 13053600000,
- 15645600000,
- 18324000000,
- 21002400000,
- 23594400000
- ]
- },
- {
- "schedule": "20 20 * * *",
- "triggerTimes": [
- 73200000,
- 159600000,
- 246000000,
- 332400000,
- 418800000,
- 505200000,
- 591600000,
- 678000000,
- 764400000,
- 850800000
- ]
- },
- {
- "schedule": "45 1 * * *",
- "triggerTimes": [
- 6300000,
- 92700000,
- 179100000,
- 265500000,
- 351900000,
- 438300000,
- 524700000,
- 611100000,
- 697500000,
- 783900000
- ]
- },
- {
- "schedule": "3-59/5 * * * *",
- "triggerTimes": [
- 180000,
- 480000,
- 780000,
- 1080000,
- 1380000,
- 1680000,
- 1980000,
- 2280000,
- 2580000,
- 2880000
- ]
- },
- {
- "schedule": "21 * * * *",
- "triggerTimes": [
- 1260000,
- 4860000,
- 8460000,
- 12060000,
- 15660000,
- 19260000,
- 22860000,
- 26460000,
- 30060000,
- 33660000
- ]
- },
- {
- "schedule": "37 */1 * * *",
- "triggerTimes": [
- 2220000,
- 5820000,
- 9420000,
- 13020000,
- 16620000,
- 20220000,
- 23820000,
- 27420000,
- 31020000,
- 34620000
- ]
- },
- {
- "schedule": "12 3 * * 1,3,5",
- "triggerTimes": [
- 97920000,
- 357120000,
- 529920000,
- 702720000,
- 961920000,
- 1134720000,
- 1307520000,
- 1566720000,
- 1739520000,
- 1912320000
- ]
- },
- {
- "schedule": "10 * * * *",
- "triggerTimes": [
- 600000,
- 4200000,
- 7800000,
- 11400000,
- 15000000,
- 18600000,
- 22200000,
- 25800000,
- 29400000,
- 33000000
- ]
- },
- {
- "schedule": "*/4 * * * *",
- "triggerTimes": [
- 240000,
- 480000,
- 720000,
- 960000,
- 1200000,
- 1440000,
- 1680000,
- 1920000,
- 2160000,
- 2400000
- ]
- },
- {
- "schedule": "36 * * * *",
- "triggerTimes": [
- 2160000,
- 5760000,
- 9360000,
- 12960000,
- 16560000,
- 20160000,
- 23760000,
- 27360000,
- 30960000,
- 34560000
- ]
- },
- {
- "schedule": "10 7 * * *",
- "triggerTimes": [
- 25800000,
- 112200000,
- 198600000,
- 285000000,
- 371400000,
- 457800000,
- 544200000,
- 630600000,
- 717000000,
- 803400000
- ]
- },
- {
- "schedule": "55 6 * * *",
- "triggerTimes": [
- 24900000,
- 111300000,
- 197700000,
- 284100000,
- 370500000,
- 456900000,
- 543300000,
- 629700000,
- 716100000,
- 802500000
- ]
- },
- {
- "schedule": "0 */2 * * *",
- "triggerTimes": [
- 7200000,
- 14400000,
- 21600000,
- 28800000,
- 36000000,
- 43200000,
- 50400000,
- 57600000,
- 64800000,
- 72000000
- ]
- },
- {
- "schedule": "0 5 * * *",
- "triggerTimes": [
- 18000000,
- 104400000,
- 190800000,
- 277200000,
- 363600000,
- 450000000,
- 536400000,
- 622800000,
- 709200000,
- 795600000
- ]
- },
- {
- "schedule": "22 */4 * * *",
- "triggerTimes": [
- 1320000,
- 15720000,
- 30120000,
- 44520000,
- 58920000,
- 73320000,
- 87720000,
- 102120000,
- 116520000,
- 130920000
- ]
- },
- {
- "schedule": "17 */2 * * *",
- "triggerTimes": [
- 1020000,
- 8220000,
- 15420000,
- 22620000,
- 29820000,
- 37020000,
- 44220000,
- 51420000,
- 58620000,
- 65820000
- ]
- },
- {
- "schedule": "25 * * * *",
- "triggerTimes": [
- 1500000,
- 5100000,
- 8700000,
- 12300000,
- 15900000,
- 19500000,
- 23100000,
- 26700000,
- 30300000,
- 33900000
- ]
- },
- {
- "schedule": "*/6 * * * *",
- "triggerTimes": [
- 360000,
- 720000,
- 1080000,
- 1440000,
- 1800000,
- 2160000,
- 2520000,
- 2880000,
- 3240000,
- 3600000
- ]
- },
- {
- "schedule": "5 * * * *",
- "triggerTimes": [
- 300000,
- 3900000,
- 7500000,
- 11100000,
- 14700000,
- 18300000,
- 21900000,
- 25500000,
- 29100000,
- 32700000
- ]
- },
- {
- "schedule": "0 2 * * *",
- "triggerTimes": [
- 7200000,
- 93600000,
- 180000000,
- 266400000,
- 352800000,
- 439200000,
- 525600000,
- 612000000,
- 698400000,
- 784800000
- ]
- },
- {
- "schedule": "0 * * * *",
- "triggerTimes": [
- 3600000,
- 7200000,
- 10800000,
- 14400000,
- 18000000,
- 21600000,
- 25200000,
- 28800000,
- 32400000,
- 36000000
- ]
- },
- {
- "schedule": "0 14 * * *,,",
- "triggerTimes": [
- 50400000,
- 136800000,
- 223200000,
- 309600000,
- 396000000,
- 482400000,
- 568800000,
- 655200000,
- 741600000,
- 828000000
- ]
- },
- {
- "schedule": "30 02,08,12 * * *",
- "triggerTimes": [
- 9000000,
- 30600000,
- 45000000,
- 95400000,
- 117000000,
- 131400000,
- 181800000,
- 203400000,
- 217800000,
- 268200000
- ]
- },
- {
- "schedule": "44 23 * * *",
- "triggerTimes": [
- 85440000,
- 171840000,
- 258240000,
- 344640000,
- 431040000,
- 517440000,
- 603840000,
- 690240000,
- 776640000,
- 863040000
- ]
- },
- {
- "schedule": "0 */4 * * *",
- "triggerTimes": [
- 14400000,
- 28800000,
- 43200000,
- 57600000,
- 72000000,
- 86400000,
- 100800000,
- 115200000,
- 129600000,
- 144000000
- ]
- },
- {
- "schedule": "0 12 * * *",
- "triggerTimes": [
- 43200000,
- 129600000,
- 216000000,
- 302400000,
- 388800000,
- 475200000,
- 561600000,
- 648000000,
- 734400000,
- 820800000
- ]
- },
- {
- "schedule": "*/2 * * * *",
- "triggerTimes": [
- 120000,
- 240000,
- 360000,
- 480000,
- 600000,
- 720000,
- 840000,
- 960000,
- 1080000,
- 1200000
- ]
- },
- {
- "schedule": "22 1 * * *",
- "triggerTimes": [
- 4920000,
- 91320000,
- 177720000,
- 264120000,
- 350520000,
- 436920000,
- 523320000,
- 609720000,
- 696120000,
- 782520000
- ]
- },
- {
- "schedule": "45 * * * *",
- "triggerTimes": [
- 2700000,
- 6300000,
- 9900000,
- 13500000,
- 17100000,
- 20700000,
- 24300000,
- 27900000,
- 31500000,
- 35100000
- ]
- },
- {
- "schedule": "00 23 * * *",
- "triggerTimes": [
- 82800000,
- 169200000,
- 255600000,
- 342000000,
- 428400000,
- 514800000,
- 601200000,
- 687600000,
- 774000000,
- 860400000
- ]
- },
- {
- "schedule": "3,6,9,12,18,21,24,27,33,36,39,42,48,51,54,57 * * * *",
- "triggerTimes": [
- 180000,
- 360000,
- 540000,
- 720000,
- 1080000,
- 1260000,
- 1440000,
- 1620000,
- 1980000,
- 2160000
- ]
- },
- {
- "schedule": "32 1 * * *",
- "triggerTimes": [
- 5520000,
- 91920000,
- 178320000,
- 264720000,
- 351120000,
- 437520000,
- 523920000,
- 610320000,
- 696720000,
- 783120000
- ]
- },
- {
- "schedule": "35 */2 * * *",
- "triggerTimes": [
- 2100000,
- 9300000,
- 16500000,
- 23700000,
- 30900000,
- 38100000,
- 45300000,
- 52500000,
- 59700000,
- 66900000
- ]
- },
- {
- "schedule": "27 1 * * *",
- "triggerTimes": [
- 5220000,
- 91620000,
- 178020000,
- 264420000,
- 350820000,
- 437220000,
- 523620000,
- 610020000,
- 696420000,
- 782820000
- ]
- },
- {
- "schedule": "0 21 * * 3",
- "triggerTimes": [
- 594000000,
- 1198800000,
- 1803600000,
- 2408400000,
- 3013200000,
- 3618000000,
- 4222800000,
- 4827600000,
- 5432400000,
- 6037200000
- ]
- },
- {
- "schedule": "55 03 * * *",
- "triggerTimes": [
- 14100000,
- 100500000,
- 186900000,
- 273300000,
- 359700000,
- 446100000,
- 532500000,
- 618900000,
- 705300000,
- 791700000
- ]
- },
- {
- "schedule": "0 23 2-31 * *",
- "triggerTimes": [
- 169200000,
- 255600000,
- 342000000,
- 428400000,
- 514800000,
- 601200000,
- 687600000,
- 774000000,
- 860400000,
- 946800000
- ]
- },
- {
- "schedule": "09 11 * * *",
- "triggerTimes": [
- 40140000,
- 126540000,
- 212940000,
- 299340000,
- 385740000,
- 472140000,
- 558540000,
- 644940000,
- 731340000,
- 817740000
- ]
- },
- {
- "schedule": "0 14 * * *",
- "triggerTimes": [
- 50400000,
- 136800000,
- 223200000,
- 309600000,
- 396000000,
- 482400000,
- 568800000,
- 655200000,
- 741600000,
- 828000000
- ]
- },
- {
- "schedule": "20 2,12,22 * * *",
- "triggerTimes": [
- 8400000,
- 44400000,
- 80400000,
- 94800000,
- 130800000,
- 166800000,
- 181200000,
- 217200000,
- 253200000,
- 267600000
- ]
- },
- {
- "schedule": "2,6,10,14,18,22,26,30,34,38,42,46,50,54,58 * * * *",
- "triggerTimes": [
- 120000,
- 360000,
- 600000,
- 840000,
- 1080000,
- 1320000,
- 1560000,
- 1800000,
- 2040000,
- 2280000
- ]
- },
- {
- "schedule": "1 16,18,20 * * *",
- "triggerTimes": [
- 57660000,
- 64860000,
- 72060000,
- 144060000,
- 151260000,
- 158460000,
- 230460000,
- 237660000,
- 244860000,
- 316860000
- ]
- },
- {
- "schedule": "30 */6 * * *",
- "triggerTimes": [
- 1800000,
- 23400000,
- 45000000,
- 66600000,
- 88200000,
- 109800000,
- 131400000,
- 153000000,
- 174600000,
- 196200000
- ]
- },
- {
- "schedule": "00 06,15 * * *",
- "triggerTimes": [
- 21600000,
- 54000000,
- 108000000,
- 140400000,
- 194400000,
- 226800000,
- 280800000,
- 313200000,
- 367200000,
- 399600000
- ]
- },
- {
- "schedule": "52 4,10,16,22 * * *",
- "triggerTimes": [
- 17520000,
- 39120000,
- 60720000,
- 82320000,
- 103920000,
- 125520000,
- 147120000,
- 168720000,
- 190320000,
- 211920000
- ]
- },
- {
- "schedule": "37 1 * * *",
- "triggerTimes": [
- 5820000,
- 92220000,
- 178620000,
- 265020000,
- 351420000,
- 437820000,
- 524220000,
- 610620000,
- 697020000,
- 783420000
- ]
- },
- {
- "schedule": "10 10,14 * * *",
- "triggerTimes": [
- 36600000,
- 51000000,
- 123000000,
- 137400000,
- 209400000,
- 223800000,
- 295800000,
- 310200000,
- 382200000,
- 396600000
- ]
- },
- {
- "schedule": "2,7,12,17,22,27,32,37,42,47,52,57 * * * *",
- "triggerTimes": [
- 120000,
- 420000,
- 720000,
- 1020000,
- 1320000,
- 1620000,
- 1920000,
- 2220000,
- 2520000,
- 2820000
- ]
- },
- {
- "schedule": "0 21 * * *",
- "triggerTimes": [
- 75600000,
- 162000000,
- 248400000,
- 334800000,
- 421200000,
- 507600000,
- 594000000,
- 680400000,
- 766800000,
- 853200000
- ]
- },
- {
- "schedule": "25 * * * *",
- "triggerTimes": [
- 1500000,
- 5100000,
- 8700000,
- 12300000,
- 15900000,
- 19500000,
- 23100000,
- 26700000,
- 30300000,
- 33900000
- ]
- },
- {
- "schedule": "0 15 * * *,,",
- "triggerTimes": [
- 54000000,
- 140400000,
- 226800000,
- 313200000,
- 399600000,
- 486000000,
- 572400000,
- 658800000,
- 745200000,
- 831600000
- ]
- },
- {
- "schedule": "13 9,21 * * *",
- "triggerTimes": [
- 33180000,
- 76380000,
- 119580000,
- 162780000,
- 205980000,
- 249180000,
- 292380000,
- 335580000,
- 378780000,
- 421980000
- ]
- },
- {
- "schedule": "10 * * * *",
- "triggerTimes": [
- 600000,
- 4200000,
- 7800000,
- 11400000,
- 15000000,
- 18600000,
- 22200000,
- 25800000,
- 29400000,
- 33000000
- ]
- },
- {
- "schedule": "12 18 * * 1,3,5",
- "triggerTimes": [
- 151920000,
- 411120000,
- 583920000,
- 756720000,
- 1015920000,
- 1188720000,
- 1361520000,
- 1620720000,
- 1793520000,
- 1966320000
- ]
- },
- {
- "schedule": "0 17-19 * * 1",
- "triggerTimes": [
- 406800000,
- 410400000,
- 414000000,
- 1011600000,
- 1015200000,
- 1018800000,
- 1616400000,
- 1620000000,
- 1623600000,
- 2221200000
- ]
- },
- {
- "schedule": "0 10 * * *",
- "triggerTimes": [
- 36000000,
- 122400000,
- 208800000,
- 295200000,
- 381600000,
- 468000000,
- 554400000,
- 640800000,
- 727200000,
- 813600000
- ]
- },
- {
- "schedule": "00 00 * * *",
- "triggerTimes": [
- 86400000,
- 172800000,
- 259200000,
- 345600000,
- 432000000,
- 518400000,
- 604800000,
- 691200000,
- 777600000,
- 864000000
- ]
- },
- {
- "schedule": "25 16,17,18,22 * * *",
- "triggerTimes": [
- 59100000,
- 62700000,
- 66300000,
- 80700000,
- 145500000,
- 149100000,
- 152700000,
- 167100000,
- 231900000,
- 235500000
- ]
- },
- {
- "schedule": "23 6,18 * * *",
- "triggerTimes": [
- 22980000,
- 66180000,
- 109380000,
- 152580000,
- 195780000,
- 238980000,
- 282180000,
- 325380000,
- 368580000,
- 411780000
- ]
- },
- {
- "schedule": "17 1,9,17 * * 0",
- "triggerTimes": [
- 263820000,
- 292620000,
- 321420000,
- 868620000,
- 897420000,
- 926220000,
- 1473420000,
- 1502220000,
- 1531020000,
- 2078220000
- ]
- },
- {
- "schedule": "00 16 * * *",
- "triggerTimes": [
- 57600000,
- 144000000,
- 230400000,
- 316800000,
- 403200000,
- 489600000,
- 576000000,
- 662400000,
- 748800000,
- 835200000
- ]
- },
- {
- "schedule": "*/3 * * * *",
- "triggerTimes": [
- 180000,
- 360000,
- 540000,
- 720000,
- 900000,
- 1080000,
- 1260000,
- 1440000,
- 1620000,
- 1800000
- ]
- },
- {
- "schedule": "19 * * * *",
- "triggerTimes": [
- 1140000,
- 4740000,
- 8340000,
- 11940000,
- 15540000,
- 19140000,
- 22740000,
- 26340000,
- 29940000,
- 33540000
- ]
- },
- {
- "schedule": "15 * * * *",
- "triggerTimes": [
- 900000,
- 4500000,
- 8100000,
- 11700000,
- 15300000,
- 18900000,
- 22500000,
- 26100000,
- 29700000,
- 33300000
- ]
- },
- {
- "schedule": "*/15 * * * *",
- "triggerTimes": [
- 900000,
- 1800000,
- 2700000,
- 3600000,
- 4500000,
- 5400000,
- 6300000,
- 7200000,
- 8100000,
- 9000000
- ]
- },
- {
- "schedule": "0 22 * * 1",
- "triggerTimes": [
- 424800000,
- 1029600000,
- 1634400000,
- 2239200000,
- 2844000000,
- 3448800000,
- 4053600000,
- 4658400000,
- 5263200000,
- 5868000000
- ]
- },
- {
- "schedule": "15 * * * *",
- "triggerTimes": [
- 900000,
- 4500000,
- 8100000,
- 11700000,
- 15300000,
- 18900000,
- 22500000,
- 26100000,
- 29700000,
- 33300000
- ]
- },
- {
- "schedule": "20 04 * * *",
- "triggerTimes": [
- 15600000,
- 102000000,
- 188400000,
- 274800000,
- 361200000,
- 447600000,
- 534000000,
- 620400000,
- 706800000,
- 793200000
- ]
- },
- {
- "schedule": "30 0,12 * * *",
- "triggerTimes": [
- 1800000,
- 45000000,
- 88200000,
- 131400000,
- 174600000,
- 217800000,
- 261000000,
- 304200000,
- 347400000,
- 390600000
- ]
- },
- {
- "schedule": "15 */4 * * *",
- "triggerTimes": [
- 900000,
- 15300000,
- 29700000,
- 44100000,
- 58500000,
- 72900000,
- 87300000,
- 101700000,
- 116100000,
- 130500000
- ]
- },
- {
- "schedule": "29 16,17,18,22 * * *",
- "triggerTimes": [
- 59340000,
- 62940000,
- 66540000,
- 80940000,
- 145740000,
- 149340000,
- 152940000,
- 167340000,
- 232140000,
- 235740000
- ]
- },
- {
- "schedule": "37 */3 * * *",
- "triggerTimes": [
- 2220000,
- 13020000,
- 23820000,
- 34620000,
- 45420000,
- 56220000,
- 67020000,
- 77820000,
- 88620000,
- 99420000
- ]
- },
- {
- "schedule": "*/15 * * * *",
- "triggerTimes": [
- 900000,
- 1800000,
- 2700000,
- 3600000,
- 4500000,
- 5400000,
- 6300000,
- 7200000,
- 8100000,
- 9000000
- ]
- },
- {
- "schedule": "35 23 * * *",
- "triggerTimes": [
- 84900000,
- 171300000,
- 257700000,
- 344100000,
- 430500000,
- 516900000,
- 603300000,
- 689700000,
- 776100000,
- 862500000
- ]
- },
- {
- "schedule": "0 17 * * *",
- "triggerTimes": [
- 61200000,
- 147600000,
- 234000000,
- 320400000,
- 406800000,
- 493200000,
- 579600000,
- 666000000,
- 752400000,
- 838800000
- ]
- },
- {
- "schedule": "0 22 * * *",
- "triggerTimes": [
- 79200000,
- 165600000,
- 252000000,
- 338400000,
- 424800000,
- 511200000,
- 597600000,
- 684000000,
- 770400000,
- 856800000
- ]
- },
- {
- "schedule": "0 11 * * *",
- "triggerTimes": [
- 39600000,
- 126000000,
- 212400000,
- 298800000,
- 385200000,
- 471600000,
- 558000000,
- 644400000,
- 730800000,
- 817200000
- ]
- },
- {
- "schedule": "30 * * * *",
- "triggerTimes": [
- 1800000,
- 5400000,
- 9000000,
- 12600000,
- 16200000,
- 19800000,
- 23400000,
- 27000000,
- 30600000,
- 34200000
- ]
- },
- {
- "schedule": "41 * * * *",
- "triggerTimes": [
- 2460000,
- 6060000,
- 9660000,
- 13260000,
- 16860000,
- 20460000,
- 24060000,
- 27660000,
- 31260000,
- 34860000
- ]
- },
- {
- "schedule": "45 23 * * *",
- "triggerTimes": [
- 85500000,
- 171900000,
- 258300000,
- 344700000,
- 431100000,
- 517500000,
- 603900000,
- 690300000,
- 776700000,
- 863100000
- ]
- },
- {
- "schedule": "*/2 * * * *",
- "triggerTimes": [
- 120000,
- 240000,
- 360000,
- 480000,
- 600000,
- 720000,
- 840000,
- 960000,
- 1080000,
- 1200000
- ]
- },
- {
- "schedule": "0 0,3,6,9,12,15,18,21 * * *",
- "triggerTimes": [
- 10800000,
- 21600000,
- 32400000,
- 43200000,
- 54000000,
- 64800000,
- 75600000,
- 86400000,
- 97200000,
- 108000000
- ]
- },
- {
- "schedule": "0,30 * * * *",
- "triggerTimes": [
- 1800000,
- 3600000,
- 5400000,
- 7200000,
- 9000000,
- 10800000,
- 12600000,
- 14400000,
- 16200000,
- 18000000
- ]
- },
- {
- "schedule": "17 * * * *",
- "triggerTimes": [
- 1020000,
- 4620000,
- 8220000,
- 11820000,
- 15420000,
- 19020000,
- 22620000,
- 26220000,
- 29820000,
- 33420000
- ]
- },
- {
- "schedule": "30,45 18 * * 1",
- "triggerTimes": [
- 412200000,
- 413100000,
- 1017000000,
- 1017900000,
- 1621800000,
- 1622700000,
- 2226600000,
- 2227500000,
- 2831400000,
- 2832300000
- ]
- },
- {
- "schedule": "13,43 * * * *",
- "triggerTimes": [
- 780000,
- 2580000,
- 4380000,
- 6180000,
- 7980000,
- 9780000,
- 11580000,
- 13380000,
- 15180000,
- 16980000
- ]
- },
- {
- "schedule": "0 0 10 * *",
- "triggerTimes": [
- 777600000,
- 3456000000,
- 5875200000,
- 8553600000,
- 11145600000,
- 13824000000,
- 16416000000,
- 19094400000,
- 21772800000,
- 24364800000
- ]
- },
- {
- "schedule": "13,28,43,58 * * * *",
- "triggerTimes": [
- 780000,
- 1680000,
- 2580000,
- 3480000,
- 4380000,
- 5280000,
- 6180000,
- 7080000,
- 7980000,
- 8880000
- ]
- },
- {
- "schedule": "17 9,13,22 * * *",
- "triggerTimes": [
- 33420000,
- 47820000,
- 80220000,
- 119820000,
- 134220000,
- 166620000,
- 206220000,
- 220620000,
- 253020000,
- 292620000
- ]
- },
- {
- "schedule": "10 8,12 * * *",
- "triggerTimes": [
- 29400000,
- 43800000,
- 115800000,
- 130200000,
- 202200000,
- 216600000,
- 288600000,
- 303000000,
- 375000000,
- 389400000
- ]
- },
- {
- "schedule": "*/5 * * * *",
- "triggerTimes": [
- 300000,
- 600000,
- 900000,
- 1200000,
- 1500000,
- 1800000,
- 2100000,
- 2400000,
- 2700000,
- 3000000
- ]
- },
- {
- "schedule": "5,20,35,50 * * * *",
- "triggerTimes": [
- 300000,
- 1200000,
- 2100000,
- 3000000,
- 3900000,
- 4800000,
- 5700000,
- 6600000,
- 7500000,
- 8400000
- ]
- },
- {
- "schedule": "00 */2 * * *",
- "triggerTimes": [
- 7200000,
- 14400000,
- 21600000,
- 28800000,
- 36000000,
- 43200000,
- 50400000,
- 57600000,
- 64800000,
- 72000000
- ]
- },
- {
- "schedule": "23 * * * *",
- "triggerTimes": [
- 1380000,
- 4980000,
- 8580000,
- 12180000,
- 15780000,
- 19380000,
- 22980000,
- 26580000,
- 30180000,
- 33780000
- ]
- },
- {
- "schedule": "7 12 * * *",
- "triggerTimes": [
- 43620000,
- 130020000,
- 216420000,
- 302820000,
- 389220000,
- 475620000,
- 562020000,
- 648420000,
- 734820000,
- 821220000
- ]
- },
- {
- "schedule": "*/1 * * * *",
- "triggerTimes": [
- 60000,
- 120000,
- 180000,
- 240000,
- 300000,
- 360000,
- 420000,
- 480000,
- 540000,
- 600000
- ]
- },
- {
- "schedule": "0,10,20,30,40,50 * * * *",
- "triggerTimes": [
- 600000,
- 1200000,
- 1800000,
- 2400000,
- 3000000,
- 3600000,
- 4200000,
- 4800000,
- 5400000,
- 6000000
- ]
- },
- {
- "schedule": "45 02,06,10,14,18,22 * * *",
- "triggerTimes": [
- 9900000,
- 24300000,
- 38700000,
- 53100000,
- 67500000,
- 81900000,
- 96300000,
- 110700000,
- 125100000,
- 139500000
- ]
- },
- {
- "schedule": "39 1 * * *",
- "triggerTimes": [
- 5940000,
- 92340000,
- 178740000,
- 265140000,
- 351540000,
- 437940000,
- 524340000,
- 610740000,
- 697140000,
- 783540000
- ]
- },
- {
- "schedule": "0 0-2 * * 2-6",
- "triggerTimes": [
- 3600000,
- 7200000,
- 86400000,
- 90000000,
- 93600000,
- 172800000,
- 176400000,
- 180000000,
- 432000000,
- 435600000
- ]
- },
- {
- "schedule": "35,50 * * * *",
- "triggerTimes": [
- 2100000,
- 3000000,
- 5700000,
- 6600000,
- 9300000,
- 10200000,
- 12900000,
- 13800000,
- 16500000,
- 17400000
- ]
- },
- {
- "schedule": "0 3 1 * *",
- "triggerTimes": [
- 10800000,
- 2689200000,
- 5108400000,
- 7786800000,
- 10378800000,
- 13057200000,
- 15649200000,
- 18327600000,
- 21006000000,
- 23598000000
- ]
- },
- {
- "schedule": "5 5 * * *",
- "triggerTimes": [
- 18300000,
- 104700000,
- 191100000,
- 277500000,
- 363900000,
- 450300000,
- 536700000,
- 623100000,
- 709500000,
- 795900000
- ]
- },
- {
- "schedule": "18 8 * * *",
- "triggerTimes": [
- 29880000,
- 116280000,
- 202680000,
- 289080000,
- 375480000,
- 461880000,
- 548280000,
- 634680000,
- 721080000,
- 807480000
- ]
- },
- {
- "schedule": "0 9 * * *",
- "triggerTimes": [
- 32400000,
- 118800000,
- 205200000,
- 291600000,
- 378000000,
- 464400000,
- 550800000,
- 637200000,
- 723600000,
- 810000000
- ]
- },
- {
- "schedule": "*/1 * * * *",
- "triggerTimes": [
- 60000,
- 120000,
- 180000,
- 240000,
- 300000,
- 360000,
- 420000,
- 480000,
- 540000,
- 600000
- ]
- },
- {
- "schedule": "50 8,12,21 * * *",
- "triggerTimes": [
- 31800000,
- 46200000,
- 78600000,
- 118200000,
- 132600000,
- 165000000,
- 204600000,
- 219000000,
- 251400000,
- 291000000
- ]
- },
- {
- "schedule": "29 9,21 * * *",
- "triggerTimes": [
- 34140000,
- 77340000,
- 120540000,
- 163740000,
- 206940000,
- 250140000,
- 293340000,
- 336540000,
- 379740000,
- 422940000
- ]
- },
- {
- "schedule": "40 * * * *",
- "triggerTimes": [
- 2400000,
- 6000000,
- 9600000,
- 13200000,
- 16800000,
- 20400000,
- 24000000,
- 27600000,
- 31200000,
- 34800000
- ]
- },
- {
- "schedule": "8 21 * * *",
- "triggerTimes": [
- 76080000,
- 162480000,
- 248880000,
- 335280000,
- 421680000,
- 508080000,
- 594480000,
- 680880000,
- 767280000,
- 853680000
- ]
- },
- {
- "schedule": "0 6 * * *",
- "triggerTimes": [
- 21600000,
- 108000000,
- 194400000,
- 280800000,
- 367200000,
- 453600000,
- 540000000,
- 626400000,
- 712800000,
- 799200000
- ]
- },
- {
- "schedule": "30 0-23/2 * * *",
- "triggerTimes": [
- 1800000,
- 9000000,
- 16200000,
- 23400000,
- 30600000,
- 37800000,
- 45000000,
- 52200000,
- 59400000,
- 66600000
- ]
- },
- {
- "schedule": "0 14,22 * * *",
- "triggerTimes": [
- 50400000,
- 79200000,
- 136800000,
- 165600000,
- 223200000,
- 252000000,
- 309600000,
- 338400000,
- 396000000,
- 424800000
- ]
- },
- {
- "schedule": "0 */1 * * *",
- "triggerTimes": [
- 3600000,
- 7200000,
- 10800000,
- 14400000,
- 18000000,
- 21600000,
- 25200000,
- 28800000,
- 32400000,
- 36000000
- ]
- },
- {
- "schedule": "0 1 * * 1",
- "triggerTimes": [
- 349200000,
- 954000000,
- 1558800000,
- 2163600000,
- 2768400000,
- 3373200000,
- 3978000000,
- 4582800000,
- 5187600000,
- 5792400000
- ]
- },
- {
- "schedule": "0 8 * * *",
- "triggerTimes": [
- 28800000,
- 115200000,
- 201600000,
- 288000000,
- 374400000,
- 460800000,
- 547200000,
- 633600000,
- 720000000,
- 806400000
- ]
- },
- {
- "schedule": "01 17 * * *",
- "triggerTimes": [
- 61260000,
- 147660000,
- 234060000,
- 320460000,
- 406860000,
- 493260000,
- 579660000,
- 666060000,
- 752460000,
- 838860000
- ]
- },
- {
- "schedule": "13 * * * *",
- "triggerTimes": [
- 780000,
- 4380000,
- 7980000,
- 11580000,
- 15180000,
- 18780000,
- 22380000,
- 25980000,
- 29580000,
- 33180000
- ]
- }
-]
[5/5] git commit: Revert "AURORA-132: Cron system based on Quartz"
Posted by ke...@apache.org.
Revert "AURORA-132: Cron system based on Quartz"
This reverts commit c285f2f83dc769143bc4a3be67e3d53b8fc51418.
Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/5de2b1ab
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/5de2b1ab
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/5de2b1ab
Branch: refs/heads/master
Commit: 5de2b1ab36ca776f684d3fb6784499ac8490e9a2
Parents: 53dc494
Author: Kevin Sweeney <ke...@apache.org>
Authored: Wed Apr 23 18:17:53 2014 -0700
Committer: Kevin Sweeney <ke...@apache.org>
Committed: Wed Apr 23 18:17:53 2014 -0700
----------------------------------------------------------------------
build.gradle | 1 -
.../aurora/scheduler/MesosTaskFactory.java | 2 +-
.../aurora/scheduler/app/SchedulerMain.java | 20 +-
.../aurora/scheduler/async/TaskGroups.java | 2 +-
.../apache/aurora/scheduler/base/JobKeys.java | 40 +-
.../configuration/ConfigurationManager.java | 12 +-
.../aurora/scheduler/cron/CronJobManager.java | 97 -
.../aurora/scheduler/cron/CronPredictor.java | 2 +-
.../aurora/scheduler/cron/CronScheduler.java | 40 +-
.../aurora/scheduler/cron/CrontabEntryTest.java | 163 +
.../aurora/scheduler/cron/SanitizedCronJob.java | 131 -
.../scheduler/cron/noop/NoopCronModule.java | 40 +
.../scheduler/cron/noop/NoopCronPredictor.java | 33 +
.../scheduler/cron/noop/NoopCronScheduler.java | 83 +
.../scheduler/cron/quartz/AuroraCronJob.java | 231 --
.../cron/quartz/AuroraCronJobFactory.java | 49 -
.../cron/quartz/CronJobManagerImpl.java | 256 --
.../scheduler/cron/quartz/CronLifecycle.java | 114 -
.../scheduler/cron/quartz/CronModule.java | 130 -
.../cron/quartz/CronPredictorImpl.java | 46 -
.../cron/quartz/CronSchedulerImpl.java | 71 -
.../aurora/scheduler/cron/quartz/Quartz.java | 124 -
.../scheduler/cron/testing/AbstractCronIT.java | 135 +
.../org/apache/aurora/scheduler/http/Cron.java | 3 +-
.../aurora/scheduler/http/ServletModule.java | 2 +-
.../aurora/scheduler/http/StructDump.java | 15 +-
.../aurora/scheduler/state/CronJobManager.java | 484 +++
.../aurora/scheduler/state/LockManagerImpl.java | 2 +-
.../scheduler/state/SchedulerCoreImpl.java | 30 +-
.../aurora/scheduler/state/StateModule.java | 7 +
.../thrift/SchedulerThriftInterface.java | 40 +-
.../cron/testing/cron-schedule-predictions.json | 3332 ++++++++++++++++++
.../aurora/scheduler/cron/CrontabEntryTest.java | 168 -
.../scheduler/cron/ExpectedPrediction.java | 55 -
.../aurora/scheduler/cron/noop/NoopCronIT.java | 63 +
.../cron/quartz/AuroraCronJobTest.java | 174 -
.../aurora/scheduler/cron/quartz/CronIT.java | 257 --
.../cron/quartz/CronJobManagerImplTest.java | 221 --
.../cron/quartz/CronPredictorImplTest.java | 89 -
.../scheduler/cron/quartz/QuartzTestUtil.java | 78 -
.../state/BaseSchedulerCoreImplTest.java | 344 +-
.../scheduler/state/CronJobManagerTest.java | 490 +++
.../scheduler/state/LockManagerImplTest.java | 2 +-
.../thrift/SchedulerThriftInterfaceTest.java | 17 +-
.../aurora/scheduler/thrift/ThriftIT.java | 4 +-
.../scheduler/cron/expected-predictions.json | 3332 ------------------
46 files changed, 5223 insertions(+), 5808 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 831d8b3..459cd85 100644
--- a/build.gradle
+++ b/build.gradle
@@ -163,7 +163,6 @@ dependencies {
compile 'org.apache.mesos:mesos:0.17.0'
compile thriftLib
compile 'org.apache.zookeeper:zookeeper:3.3.4'
- compile 'org.quartz-scheduler:quartz:2.2.1'
compile "org.slf4j:slf4j-api:${slf4jRev}"
compile "org.slf4j:slf4j-jdk14:${slf4jRev}"
compile 'com.twitter.common.logging:log4j:0.0.7'
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/MesosTaskFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/MesosTaskFactory.java b/src/main/java/org/apache/aurora/scheduler/MesosTaskFactory.java
index bdd8c19..86bbc29 100644
--- a/src/main/java/org/apache/aurora/scheduler/MesosTaskFactory.java
+++ b/src/main/java/org/apache/aurora/scheduler/MesosTaskFactory.java
@@ -135,7 +135,7 @@ public interface MesosTaskFactory {
}
TaskInfo.Builder taskBuilder =
TaskInfo.newBuilder()
- .setName(JobKeys.canonicalString(Tasks.ASSIGNED_TO_JOB_KEY.apply(task)))
+ .setName(JobKeys.toPath(Tasks.ASSIGNED_TO_JOB_KEY.apply(task)))
.setTaskId(TaskID.newBuilder().setValue(task.getTaskId()))
.setSlaveId(slaveId)
.addAllResources(resources)
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java b/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
index da6f5e5..bf3d7a3 100644
--- a/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
+++ b/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
@@ -59,7 +59,9 @@ import org.apache.aurora.scheduler.DriverFactory;
import org.apache.aurora.scheduler.DriverFactory.DriverFactoryImpl;
import org.apache.aurora.scheduler.MesosTaskFactory.ExecutorConfig;
import org.apache.aurora.scheduler.SchedulerLifecycle;
-import org.apache.aurora.scheduler.cron.quartz.CronModule;
+import org.apache.aurora.scheduler.cron.CronPredictor;
+import org.apache.aurora.scheduler.cron.CronScheduler;
+import org.apache.aurora.scheduler.cron.noop.NoopCronModule;
import org.apache.aurora.scheduler.local.IsolatedSchedulerModule;
import org.apache.aurora.scheduler.log.mesos.MesosLogStreamModule;
import org.apache.aurora.scheduler.storage.backup.BackupModule;
@@ -113,7 +115,17 @@ public class SchedulerMain extends AbstractApplication {
.add(CapabilityValidator.class)
.build();
- // TODO(Suman Karumuri): Pass in AUTH as extra module
+ @CmdLine(name = "cron_module",
+ help = "A Guice module to provide cron bindings. NOTE: The default is a no-op.")
+ private static final Arg<? extends Class<? extends Module>> CRON_MODULE =
+ Arg.create(NoopCronModule.class);
+
+ private static final Iterable<Class<?>> CRON_MODULE_CLASSES = ImmutableList.<Class<?>>builder()
+ .add(CronPredictor.class)
+ .add(CronScheduler.class)
+ .build();
+
+ // TODO(Suman Karumuri): Pass in AUTH and CRON modules as extra modules
@CmdLine(name = "extra_modules",
help = "A list of modules that provide additional functionality.")
private static final Arg<List<Class<? extends Module>>> EXTRA_MODULES =
@@ -139,7 +151,8 @@ public class SchedulerMain extends AbstractApplication {
private static Iterable<? extends Module> getExtraModules() {
Builder<Module> modules = ImmutableList.builder();
- modules.add(Modules.wrapInPrivateModule(AUTH_MODULE.get(), AUTH_MODULE_CLASSES));
+ modules.add(Modules.wrapInPrivateModule(AUTH_MODULE.get(), AUTH_MODULE_CLASSES))
+ .add(Modules.wrapInPrivateModule(CRON_MODULE.get(), CRON_MODULE_CLASSES));
for (Class<? extends Module> moduleClass : EXTRA_MODULES.get()) {
modules.add(Modules.getModule(moduleClass));
@@ -160,7 +173,6 @@ public class SchedulerMain extends AbstractApplication {
.addAll(getExtraModules())
.add(new LogStorageModule())
.add(new MemStorageModule(Bindings.annotatedKeyFactory(LogStorage.WriteBehind.class)))
- .add(new CronModule())
.add(new ThriftModule())
.add(new ThriftAuthModule())
.build();
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/async/TaskGroups.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/async/TaskGroups.java b/src/main/java/org/apache/aurora/scheduler/async/TaskGroups.java
index ef73032..6aff091 100644
--- a/src/main/java/org/apache/aurora/scheduler/async/TaskGroups.java
+++ b/src/main/java/org/apache/aurora/scheduler/async/TaskGroups.java
@@ -243,7 +243,7 @@ public class TaskGroups implements EventSubscriber {
@Override
public String toString() {
- return JobKeys.canonicalString(Tasks.INFO_TO_JOB_KEY.apply(canonicalTask));
+ return JobKeys.toPath(Tasks.INFO_TO_JOB_KEY.apply(canonicalTask));
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/base/JobKeys.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/base/JobKeys.java b/src/main/java/org/apache/aurora/scheduler/base/JobKeys.java
index c81ac62..db1bec4 100644
--- a/src/main/java/org/apache/aurora/scheduler/base/JobKeys.java
+++ b/src/main/java/org/apache/aurora/scheduler/base/JobKeys.java
@@ -15,20 +15,17 @@
*/
package org.apache.aurora.scheduler.base;
-import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.base.Functions;
-import com.google.common.base.Joiner;
import com.google.common.base.Optional;
-import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import org.apache.aurora.gen.JobKey;
import org.apache.aurora.gen.TaskQuery;
-import org.apache.aurora.scheduler.configuration.ConfigurationManager;
import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
import org.apache.aurora.scheduler.storage.entities.IJobKey;
import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
@@ -86,9 +83,9 @@ public final class JobKeys {
*/
public static boolean isValid(@Nullable IJobKey jobKey) {
return jobKey != null
- && ConfigurationManager.isGoodIdentifier(jobKey.getRole())
- && ConfigurationManager.isGoodIdentifier(jobKey.getEnvironment())
- && ConfigurationManager.isGoodIdentifier(jobKey.getName());
+ && !Strings.isNullOrEmpty(jobKey.getRole())
+ && !Strings.isNullOrEmpty(jobKey.getEnvironment())
+ && !Strings.isNullOrEmpty(jobKey.getName());
}
/**
@@ -135,32 +132,25 @@ public final class JobKeys {
}
/**
- * Create a "/"-delimited representation of job key usable as a unique identifier in this cluster.
+ * Create a "/"-delimited String representation of a job key, suitable for logging but not
+ * necessarily suitable for use as a unique identifier.
*
- * It is guaranteed that {@code k.equals(JobKeys.parse(JobKeys.canonicalString(k))}.
- *
- * @see #parse(String)
* @param jobKey Key to represent.
- * @return Canonical "/"-delimited representation of the key.
+ * @return "/"-delimited representation of the key.
*/
- public static String canonicalString(IJobKey jobKey) {
- return Joiner.on("/").join(jobKey.getRole(), jobKey.getEnvironment(), jobKey.getName());
+ public static String toPath(IJobKey jobKey) {
+ return jobKey.getRole() + "/" + jobKey.getEnvironment() + "/" + jobKey.getName();
}
/**
- * Create a job key from a "role/environment/name" representation.
- *
- * It is guaranteed that {@code k.equals(JobKeys.parse(JobKeys.canonicalString(k))}.
+ * Create a "/"-delimited String representation of job key, suitable for logging but not
+ * necessarily suitable for use as a unique identifier.
*
- * @see #canonicalString(IJobKey)
- * @param string Input to parse.
- * @return Parsed representation.
- * @throws IllegalArgumentException when the string fails to parse.
+ * @param job Job to represent.
+ * @return "/"-delimited representation of the job's key.
*/
- public static IJobKey parse(String string) throws IllegalArgumentException {
- List<String> components = Splitter.on("/").splitToList(string);
- checkArgument(components.size() == 3);
- return from(components.get(0), components.get(1), components.get(2));
+ public static String toPath(IJobConfiguration job) {
+ return toPath(job.getKey());
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java b/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
index e5ad461..82034e0 100644
--- a/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
+++ b/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
@@ -164,15 +164,9 @@ public final class ConfigurationManager {
// Utility class.
}
- /**
- * Verifies that an identifier is an acceptable name component.
- *
- * @param identifier Identifier to check.
- * @return false if the identifier is null or invalid.
- */
- public static boolean isGoodIdentifier(@Nullable String identifier) {
- return identifier != null
- && GOOD_IDENTIFIER.matcher(identifier).matches()
+ @VisibleForTesting
+ static boolean isGoodIdentifier(String identifier) {
+ return GOOD_IDENTIFIER.matcher(identifier).matches()
&& (identifier.length() <= MAX_IDENTIFIER_LENGTH);
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/CronJobManager.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/CronJobManager.java b/src/main/java/org/apache/aurora/scheduler/cron/CronJobManager.java
deleted file mode 100644
index 7c8d5ec..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/CronJobManager.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron;
-
-import java.util.Map;
-
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-
-/**
- * Manages the persistence and scheduling of jobs that should be run periodically on a cron
- * schedule.
- */
-public interface CronJobManager {
- /**
- * Triggers execution of a job.
- *
- * @param jobKey Key of the job to start.
- * @throws CronException If the job could not be started with the cron system.
- */
- void startJobNow(IJobKey jobKey) throws CronException;
-
- /**
- * Persist a new cron job to storage and schedule it for future execution.
- *
- * @param config Cron job configuration to update to.
- * @throws CronException If a job with the same key does not exist or the job could not be
- * scheduled.
- */
- void updateJob(SanitizedCronJob config) throws CronException;
-
- /**
- * Persist a cron job to storage and schedule it for future execution.
- *
- * @param config New cron job configuration.
- * @throws CronException If a job with the same key exists or the job could not be scheduled.
- */
- void createJob(SanitizedCronJob config) throws CronException;
-
- /**
- * Get all cron jobs.
- *
- * TODO(ksweeney): Consider deprecating this and letting caller query storage directly.
- *
- * @return An immutable snapshot of cron jobs at some instant.
- */
- Iterable<IJobConfiguration> getJobs();
-
- /**
- * Test whether a job exists.
- *
- * TODO(ksweeney): Consider deprecating this and letting caller query storage directly.
- *
- * @param jobKey Key of the job to check.
- * @return false when a job does not exist in storage.
- */
- boolean hasJob(IJobKey jobKey);
-
- /**
- * Remove a job and deschedule it.
- *
- * @param jobKey Key of the job to delete.
- * @return true if a job was removed.
- */
- boolean deleteJob(IJobKey jobKey);
-
- /**
- * A list of the currently scheduled jobs and when they will run according to the underlying
- * execution engine.
- *
- * @return A map from job to the cron schedule in use for that job.
- */
- Map<IJobKey, CrontabEntry> getScheduledJobs();
-
- /**
- * The unique ID of this cron job manager, used as a prefix in the JobStore.
- *
- * TODO(ksweeney): Consider removing this from storage entirely since the JobManager abstraction
- * is gone.
- *
- * @return The unique ID of the manager.
- */
- String getManagerKey();
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/CronPredictor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/CronPredictor.java b/src/main/java/org/apache/aurora/scheduler/cron/CronPredictor.java
index 0ce60f8..df0c378 100644
--- a/src/main/java/org/apache/aurora/scheduler/cron/CronPredictor.java
+++ b/src/main/java/org/apache/aurora/scheduler/cron/CronPredictor.java
@@ -27,5 +27,5 @@ public interface CronPredictor {
* @param schedule Cron schedule to predict the next time for.
* @return A prediction for the next time a cron will run.
*/
- Date predictNextRun(CrontabEntry schedule);
+ Date predictNextRun(String schedule);
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/CronScheduler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/CronScheduler.java b/src/main/java/org/apache/aurora/scheduler/cron/CronScheduler.java
index f38dea5..56e9950 100644
--- a/src/main/java/org/apache/aurora/scheduler/cron/CronScheduler.java
+++ b/src/main/java/org/apache/aurora/scheduler/cron/CronScheduler.java
@@ -15,19 +15,49 @@
*/
package org.apache.aurora.scheduler.cron;
-import com.google.common.base.Optional;
+import javax.annotation.Nullable;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Service;
/**
* An execution manager that executes work on a cron schedule.
*/
-public interface CronScheduler {
+public interface CronScheduler extends Service {
+ /**
+ * Schedules a task on a cron schedule.
+ *
+ * @param schedule Cron-style schedule.
+ * @param task Work to run when on the cron schedule.
+ * @return A unique ID to identify the scheduled cron task.
+ * @throws CronException when there was a failure to schedule, for example if {@code schedule}
+ * is not a valid input.
+ * @throws IllegalStateException If the cron scheduler is not currently running.
+ */
+ String schedule(String schedule, Runnable task) throws CronException, IllegalStateException;
+
+ /**
+ * Removes a scheduled cron item.
+ *
+ * @param key Key previously returned from {@link #schedule(String, Runnable)}.
+ * @throws IllegalStateException If the cron scheduler is not currently running.
+ */
+ void deschedule(String key) throws IllegalStateException;
+
/**
* Gets the cron schedule associated with a scheduling key.
*
- * @param key Key previously returned from {@link #schedule(CrontabEntry, Runnable)}.
+ * @param key Key previously returned from {@link #schedule(String, Runnable)}.
* @return The task's cron schedule, if a matching task was found.
+ * @throws IllegalStateException If the cron scheduler is not currently running.
+ */
+ Optional<String> getSchedule(String key) throws IllegalStateException;
+
+ /**
+ * Checks to see if the scheduler would be accepted by the underlying scheduler.
+ *
+ * @param schedule Cron scheduler to validate.
+ * @return {@code true} if the schedule is valid.
*/
- Optional<CrontabEntry> getSchedule(IJobKey key);
+ boolean isValidSchedule(@Nullable String schedule);
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java b/src/main/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java
new file mode 100644
index 0000000..2bb848a
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright 2014 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.cron;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class CrontabEntryTest {
+ @Test
+ public void testHashCodeAndEquals() {
+
+ List<CrontabEntry> entries = ImmutableList.of(
+ CrontabEntry.parse("* * * * *"),
+ CrontabEntry.parse("0-59 * * * *"),
+ CrontabEntry.parse("0-57,58,59 * * * *"),
+ CrontabEntry.parse("* 23,1,2,4,0-22 * * *"),
+ CrontabEntry.parse("1-50,0,51-59 * * * sun-sat"));
+
+ for (CrontabEntry lhs : entries) {
+ for (CrontabEntry rhs : entries) {
+ assertEquals(lhs, rhs);
+ }
+ }
+
+ Set<CrontabEntry> equivalentEntries = Sets.newHashSet(entries);
+ assertTrue(equivalentEntries.size() == 1);
+ }
+
+ @Test
+ public void testEqualsCoverage() {
+ assertNotEquals(CrontabEntry.parse("* * * * *"), new Object());
+
+ assertNotEquals(CrontabEntry.parse("* * * * *"), CrontabEntry.parse("1 * * * *"));
+ assertEquals(CrontabEntry.parse("1,2,3 * * * *"), CrontabEntry.parse("1-3 * * * *"));
+
+ assertNotEquals(CrontabEntry.parse("* 0-22 * * *"), CrontabEntry.parse("* * * * *"));
+ assertEquals(CrontabEntry.parse("* 0-23 * * *"), CrontabEntry.parse("* * * * *"));
+
+ assertNotEquals(CrontabEntry.parse("1 1 1-30 * *"), CrontabEntry.parse("1 1 * * *"));
+ assertEquals(CrontabEntry.parse("1 1 1-31 * *"), CrontabEntry.parse("1 1 * * *"));
+
+ assertNotEquals(CrontabEntry.parse("1 1 * JAN,FEB-NOV *"), CrontabEntry.parse("1 1 * * *"));
+ assertEquals(CrontabEntry.parse("1 1 * JAN,FEB-DEC *"), CrontabEntry.parse("1 1 * * *"));
+
+ assertNotEquals(CrontabEntry.parse("* * * * SUN"), CrontabEntry.parse("* * * * SAT"));
+ assertEquals(CrontabEntry.parse("* * * * 0"), CrontabEntry.parse("* * * * SUN"));
+ }
+
+ @Test
+ public void testSkip() {
+ assertEquals(CrontabEntry.parse("*/15 * * * *"), CrontabEntry.parse("0,15,30,45 * * * *"));
+ assertEquals(
+ CrontabEntry.parse("* */2 * * *"),
+ CrontabEntry.parse("0-59 0,2,4,6,8,10,12-23/2 * * *"));
+ }
+
+ @Test
+ public void testToString() {
+ assertEquals("0-58 * * * *", CrontabEntry.parse("0,1-57,58 * * * *").toString());
+ assertEquals("* * * * *", CrontabEntry.parse("* * * * *").toString());
+ }
+
+ @Test
+ public void testWildcards() {
+ CrontabEntry wildcardMinuteEntry = CrontabEntry.parse("* 1 1 1 *");
+ assertEquals("*", wildcardMinuteEntry.getMinuteAsString());
+ assertTrue(wildcardMinuteEntry.hasWildcardMinute());
+ assertFalse(wildcardMinuteEntry.hasWildcardHour());
+ assertFalse(wildcardMinuteEntry.hasWildcardDayOfMonth());
+ assertFalse(wildcardMinuteEntry.hasWildcardMonth());
+ assertTrue(wildcardMinuteEntry.hasWildcardDayOfWeek());
+
+ CrontabEntry wildcardHourEntry = CrontabEntry.parse("1 * 1 1 *");
+ assertEquals("*", wildcardHourEntry.getHourAsString());
+ assertFalse(wildcardHourEntry.hasWildcardMinute());
+ assertTrue(wildcardHourEntry.hasWildcardHour());
+ assertFalse(wildcardHourEntry.hasWildcardDayOfMonth());
+ assertFalse(wildcardHourEntry.hasWildcardMonth());
+ assertTrue(wildcardHourEntry.hasWildcardDayOfWeek());
+
+ CrontabEntry wildcardDayOfMonth = CrontabEntry.parse("1 1 * 1 *");
+ assertEquals("*", wildcardDayOfMonth.getDayOfMonthAsString());
+ assertFalse(wildcardDayOfMonth.hasWildcardMinute());
+ assertFalse(wildcardDayOfMonth.hasWildcardHour());
+ assertTrue(wildcardDayOfMonth.hasWildcardDayOfMonth());
+ assertFalse(wildcardDayOfMonth.hasWildcardMonth());
+ assertTrue(wildcardDayOfMonth.hasWildcardDayOfWeek());
+
+ CrontabEntry wildcardMonth = CrontabEntry.parse("1 1 1 * *");
+ assertEquals("*", wildcardMonth.getMonthAsString());
+ assertFalse(wildcardMonth.hasWildcardMinute());
+ assertFalse(wildcardMonth.hasWildcardHour());
+ assertFalse(wildcardMonth.hasWildcardDayOfMonth());
+ assertTrue(wildcardMonth.hasWildcardMonth());
+ assertTrue(wildcardMonth.hasWildcardDayOfWeek());
+
+ CrontabEntry wildcardDayOfWeek = CrontabEntry.parse("1 1 1 1 *");
+ assertEquals("*", wildcardDayOfWeek.getDayOfWeekAsString());
+ assertFalse(wildcardDayOfWeek.hasWildcardMinute());
+ assertFalse(wildcardDayOfWeek.hasWildcardHour());
+ assertFalse(wildcardDayOfWeek.hasWildcardDayOfMonth());
+ assertFalse(wildcardDayOfWeek.hasWildcardMonth());
+ assertTrue(wildcardDayOfWeek.hasWildcardDayOfWeek());
+ }
+
+ @Test
+ public void testEqualsIsCanonical() {
+ String rawEntry = "* * */3 * *";
+ CrontabEntry input = CrontabEntry.parse(rawEntry);
+ assertNotEquals(
+ rawEntry + " is not the canonical form of " + input,
+ rawEntry,
+ input.toString());
+ assertEquals(
+ "The form returned by toString is canonical",
+ input.toString(),
+ CrontabEntry.parse(input.toString()).toString());
+ }
+
+ @Test
+ public void testBadEntries() {
+ List<String> badPatterns = ImmutableList.of(
+ "* * * * MON-SUN",
+ "* * **",
+ "0-59 0-59 * * *",
+ "1/1 * * * *",
+ "5 5 * MAR-JAN *",
+ "*/0 * * * *",
+ "0-59/0 * * * *",
+ "0-59/60 * * * *",
+ "* * * *, *",
+ "* * 1 * 1"
+ );
+
+ for (String pattern : badPatterns) {
+ assertNull(CrontabEntry.tryParse(pattern).orNull());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/SanitizedCronJob.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/SanitizedCronJob.java b/src/main/java/org/apache/aurora/scheduler/cron/SanitizedCronJob.java
deleted file mode 100644
index 0082932..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/SanitizedCronJob.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron;
-
-import javax.annotation.Nullable;
-
-import com.google.common.base.Optional;
-
-import org.apache.aurora.gen.CronCollisionPolicy;
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.configuration.ConfigurationManager;
-import org.apache.aurora.scheduler.configuration.SanitizedConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.commons.lang.StringUtils;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Used by functions that expect field validation before being called.
- */
-public final class SanitizedCronJob {
- private final SanitizedConfiguration config;
- private final CrontabEntry crontabEntry;
-
- private SanitizedCronJob(IJobConfiguration unsanitized)
- throws CronException, ConfigurationManager.TaskDescriptionException {
-
- this(SanitizedConfiguration.fromUnsanitized(unsanitized));
- }
-
- private SanitizedCronJob(SanitizedConfiguration config) throws CronException {
- final IJobConfiguration job = config.getJobConfig();
- if (!hasCronSchedule(job)) {
- throw new CronException(String.format(
- "Not a valid cron job, %s has no cron schedule", JobKeys.canonicalString(job.getKey())));
- }
-
- Optional<CrontabEntry> entry = CrontabEntry.tryParse(job.getCronSchedule());
- if (!entry.isPresent()) {
- throw new CronException("Invalid cron schedule: " + job.getCronSchedule());
- }
-
- this.config = config;
- this.crontabEntry = entry.get();
- }
-
- /**
- * Get the default cron collision policy.
- *
- * @param policy A (possibly null) policy.
- * @return The given policy or a default if the policy was null.
- */
- public static CronCollisionPolicy orDefault(@Nullable CronCollisionPolicy policy) {
- return Optional.fromNullable(policy).or(CronCollisionPolicy.KILL_EXISTING);
- }
-
- /**
- * Create a SanitizedCronJob from a SanitizedConfiguration. SanitizedCronJob performs additional
- * validation to ensure that the provided job contains all properties needed to run it on a
- * cron schedule.
- *
- * @param config Config to validate.
- * @return Config wrapped in defaults.
- * @throws CronException If a cron-specific validation error occured.
- */
- public static SanitizedCronJob from(SanitizedConfiguration config)
- throws CronException {
-
- return new SanitizedCronJob(config);
- }
-
- /**
- * Create a cron job from an unsanitized input job. Suitable for RPC input validation.
- *
- * @param unsanitized Unsanitized input job.
- * @return A sanitized job if all validation succeeds.
- * @throws CronException If validation fails with a cron-specific error.
- * @throws ConfigurationManager.TaskDescriptionException If validation fails with a non
- * cron-specific error.
- */
- public static SanitizedCronJob fromUnsanitized(IJobConfiguration unsanitized)
- throws CronException, ConfigurationManager.TaskDescriptionException {
-
- return new SanitizedCronJob(unsanitized);
- }
-
- /**
- * Get this job's cron collision policy.
- *
- * @return This job's cron collision policy.
- */
- public CronCollisionPolicy getCronCollisionPolicy() {
- return orDefault(config.getJobConfig().getCronCollisionPolicy());
- }
-
- private static boolean hasCronSchedule(IJobConfiguration job) {
- checkNotNull(job);
- return !StringUtils.isEmpty(job.getCronSchedule());
- }
-
- /**
- * Returns the cron schedule associated with this job.
- *
- * @return The cron schedule associated with this job.
- */
- public CrontabEntry getCrontabEntry() {
- return crontabEntry;
- }
-
- /**
- * Returns the sanitized job configuration associated with the cron job.
- *
- * @return This cron job's sanitized job configuration.
- */
- public SanitizedConfiguration getSanitizedConfig() {
- return config;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronModule.java b/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronModule.java
new file mode 100644
index 0000000..e0935f5
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronModule.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2013 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.cron.noop;
+
+import javax.inject.Singleton;
+
+import com.google.inject.AbstractModule;
+
+import org.apache.aurora.scheduler.cron.CronPredictor;
+import org.apache.aurora.scheduler.cron.CronScheduler;
+
+/**
+ * A Module to wire up a cron scheduler that does not actually schedule cron jobs.
+ *
+ * This class exists as a short term hack to get around a license compatibility issue - Real
+ * Implementation (TM) coming soon.
+ */
+public class NoopCronModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(CronScheduler.class).to(NoopCronScheduler.class);
+ bind(NoopCronScheduler.class).in(Singleton.class);
+
+ bind(CronPredictor.class).to(NoopCronPredictor.class);
+ bind(NoopCronPredictor.class).in(Singleton.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronPredictor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronPredictor.java b/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronPredictor.java
new file mode 100644
index 0000000..7b25152
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronPredictor.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2013 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.cron.noop;
+
+import java.util.Date;
+
+import org.apache.aurora.scheduler.cron.CronPredictor;
+
+/**
+ * A cron predictor that always suggests that the next run is Unix epoch time.
+ *
+ * This class exists as a short term hack to get around a license compatibility issue - Real
+ * Implementation (TM) coming soon.
+ */
+class NoopCronPredictor implements CronPredictor {
+ @Override
+ public Date predictNextRun(String schedule) {
+ return new Date(0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronScheduler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronScheduler.java b/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronScheduler.java
new file mode 100644
index 0000000..a31551c
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/cron/noop/NoopCronScheduler.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright 2013 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.cron.noop;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.AbstractIdleService;
+
+import org.apache.aurora.scheduler.cron.CronScheduler;
+
+/**
+ * A cron scheduler that accepts cron jobs but never runs them. Useful if you want to hook up an
+ * external triggering mechanism (e.g. a system cron job that calls the startCronJob RPC manually
+ * on an interval).
+ *
+ * This class exists as a short term hack to get around a license compatibility issue - Real
+ * Implementation (TM) coming soon.
+ */
+class NoopCronScheduler extends AbstractIdleService implements CronScheduler {
+ private static final Logger LOG = Logger.getLogger(NoopCronScheduler.class.getName());
+
+ // Keep a list of schedules we've seen.
+ private final Set<String> schedules = Collections.synchronizedSet(Sets.<String>newHashSet());
+
+ @Override
+ public void startUp() throws Exception {
+ LOG.warning("NO-OP cron scheduler is in use. Cron jobs submitted will not be triggered!");
+ }
+
+ @Override
+ public void shutDown() {
+ // No-op.
+ }
+
+ @Override
+ public String schedule(String schedule, Runnable task) {
+ schedules.add(schedule);
+
+ LOG.warning(String.format(
+ "NO-OP cron scheduler is in use! %s with schedule %s WILL NOT be automatically triggered!",
+ task,
+ schedule));
+
+ return schedule;
+ }
+
+ @Override
+ public void deschedule(String key) throws IllegalStateException {
+ schedules.remove(key);
+ }
+
+ @Override
+ public Optional<String> getSchedule(String key) throws IllegalStateException {
+ return schedules.contains(key)
+ ? Optional.of(key)
+ : Optional.<String>absent();
+ }
+
+ @Override
+ public boolean isValidSchedule(@Nullable String schedule) {
+ // Accept everything.
+ return schedule != null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJob.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJob.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJob.java
deleted file mode 100644
index fc02264..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJob.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.Date;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.inject.Inject;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-
-import com.twitter.common.base.Supplier;
-import com.twitter.common.stats.Stats;
-import com.twitter.common.util.BackoffHelper;
-
-import org.apache.aurora.gen.CronCollisionPolicy;
-import org.apache.aurora.gen.ScheduleStatus;
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.base.Query;
-import org.apache.aurora.scheduler.base.Tasks;
-import org.apache.aurora.scheduler.configuration.ConfigurationManager;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
-import org.apache.aurora.scheduler.state.StateManager;
-import org.apache.aurora.scheduler.storage.Storage;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
-
-import org.quartz.DisallowConcurrentExecution;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import static org.apache.aurora.gen.ScheduleStatus.KILLING;
-
-/**
- * Encapsulates the logic behind a single trigger of a single job key. Multiple executions may run
- * concurrently but only a single instance will be active at a time per job key.
- *
- * <p>
- * Executions may block for long periods of time when waiting for a kill to complete. The Quartz
- * scheduler should therefore be configured with a large number of threads.
- */
-@DisallowConcurrentExecution
-class AuroraCronJob implements Job {
- private static final Logger LOG = Logger.getLogger(AuroraCronJob.class.getName());
-
- private static final AtomicLong CRON_JOB_TRIGGERS = Stats.exportLong("cron_job_triggers");
- private static final AtomicLong CRON_JOB_MISFIRES = Stats.exportLong("cron_job_misfires");
- private static final AtomicLong CRON_JOB_PARSE_FAILURES =
- Stats.exportLong("cron_job_parse_failures");
- private static final AtomicLong CRON_JOB_COLLISIONS = Stats.exportLong("cron_job_collisions");
-
- @VisibleForTesting
- static final Optional<String> KILL_AUDIT_MESSAGE = Optional.of("Killed by cronScheduler");
-
- private final Storage storage;
- private final StateManager stateManager;
- private final CronJobManager cronJobManager;
- private final BackoffHelper delayedStartBackoff;
-
- @Inject
- AuroraCronJob(
- Config config,
- Storage storage,
- StateManager stateManager,
- CronJobManager cronJobManager) {
-
- this.storage = checkNotNull(storage);
- this.stateManager = checkNotNull(stateManager);
- this.cronJobManager = checkNotNull(cronJobManager);
- this.delayedStartBackoff = checkNotNull(config.getDelayedStartBackoff());
- }
-
- private static final class DeferredLaunch {
- private final Map<Integer, ITaskConfig> pendingTasks;
- private final Set<String> activeTaskIds;
-
- private DeferredLaunch(Map<Integer, ITaskConfig> pendingTasks, Set<String> activeTaskIds) {
- this.pendingTasks = pendingTasks;
- this.activeTaskIds = activeTaskIds;
- }
- }
-
- @Override
- public void execute(JobExecutionContext context) throws JobExecutionException {
- // We assume quartz prevents concurrent runs of this job for a given job key. This allows us
- // to avoid races where we might kill another run's tasks.
- checkState(context.getJobDetail().isConcurrentExectionDisallowed());
-
- doExecute(Quartz.auroraJobKey(context.getJobDetail().getKey()));
- }
-
- @VisibleForTesting
- void doExecute(final IJobKey key) throws JobExecutionException {
- final String path = JobKeys.canonicalString(key);
-
- final Optional<DeferredLaunch> deferredLaunch = storage.write(
- new Storage.MutateWork.Quiet<Optional<DeferredLaunch>>() {
- @Override
- public Optional<DeferredLaunch> apply(Storage.MutableStoreProvider storeProvider) {
- Optional<IJobConfiguration> config =
- storeProvider.getJobStore().fetchJob(cronJobManager.getManagerKey(), key);
- if (!config.isPresent()) {
- LOG.warning(String.format(
- "Cron was triggered for %s but no job with that key was found in storage.",
- path));
- CRON_JOB_MISFIRES.incrementAndGet();
- return Optional.absent();
- }
-
- SanitizedCronJob cronJob;
- try {
- cronJob = SanitizedCronJob.fromUnsanitized(config.get());
- } catch (ConfigurationManager.TaskDescriptionException | CronException e) {
- LOG.warning(String.format(
- "Invalid cron job for %s in storage - failed to parse with %s", key, e));
- CRON_JOB_PARSE_FAILURES.incrementAndGet();
- return Optional.absent();
- }
-
- CronCollisionPolicy collisionPolicy = cronJob.getCronCollisionPolicy();
- LOG.info(String.format(
- "Cron triggered for %s at %s with policy %s", path, new Date(), collisionPolicy));
- CRON_JOB_TRIGGERS.incrementAndGet();
-
- ImmutableMap<Integer, ITaskConfig> pendingTasks =
- ImmutableMap.copyOf(cronJob.getSanitizedConfig().getTaskConfigs());
-
- final Query.Builder activeQuery = Query.jobScoped(key).active();
- Set<String> activeTasks =
- Tasks.ids(storeProvider.getTaskStore().fetchTasks(activeQuery));
-
- if (activeTasks.isEmpty()) {
- stateManager.insertPendingTasks(pendingTasks);
- return Optional.absent();
- }
-
- CRON_JOB_COLLISIONS.incrementAndGet();
- switch (collisionPolicy) {
- case KILL_EXISTING:
- return Optional.of(new DeferredLaunch(pendingTasks, activeTasks));
-
- case RUN_OVERLAP:
- LOG.severe(String.format("Ignoring trigger for job %s with deprecated collision"
- + "policy RUN_OVERLAP due to unterminated active tasks.", path));
- return Optional.absent();
-
- case CANCEL_NEW:
- return Optional.absent();
-
- default:
- LOG.severe("Unrecognized cron collision policy: " + collisionPolicy);
- return Optional.absent();
- }
- }
- }
- );
-
- if (!deferredLaunch.isPresent()) {
- return;
- }
-
- for (String taskId : deferredLaunch.get().activeTaskIds) {
- stateManager.changeState(
- taskId,
- Optional.<ScheduleStatus>absent(),
- KILLING,
- KILL_AUDIT_MESSAGE);
- }
- LOG.info(String.format("Waiting for job to terminate before launching cron job %s.", path));
-
- final Query.Builder query = Query.taskScoped(deferredLaunch.get().activeTaskIds).active();
- try {
- // NOTE: We block the quartz execution thread here until we've successfully killed our
- // ancestor. We mitigate this by using a cached thread pool for quartz.
- delayedStartBackoff.doUntilSuccess(new Supplier<Boolean>() {
- @Override
- public Boolean get() {
- if (Storage.Util.consistentFetchTasks(storage, query).isEmpty()) {
- LOG.info("Initiating delayed launch of cron " + path);
- stateManager.insertPendingTasks(deferredLaunch.get().pendingTasks);
- return true;
- } else {
- LOG.info("Not yet safe to run cron " + path);
- return false;
- }
- }
- });
- } catch (InterruptedException e) {
- LOG.log(Level.WARNING, "Interrupted while trying to launch cron " + path, e);
- Thread.currentThread().interrupt();
- throw new JobExecutionException(e);
- }
- }
-
- static class Config {
- private final BackoffHelper delayedStartBackoff;
-
- Config(BackoffHelper delayedStartBackoff) {
- this.delayedStartBackoff = checkNotNull(delayedStartBackoff);
- }
-
- public BackoffHelper getDelayedStartBackoff() {
- return delayedStartBackoff;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobFactory.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobFactory.java
deleted file mode 100644
index c5268cb..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobFactory.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-import org.quartz.Job;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.spi.JobFactory;
-import org.quartz.spi.TriggerFiredBundle;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-/**
-* Adapter that allows AuroraCronJobs to be constructed by Guice instead of directly by quartz.
-*/
-class AuroraCronJobFactory implements JobFactory {
- private final Provider<AuroraCronJob> auroraCronJobProvider;
-
- @Inject
- AuroraCronJobFactory(Provider<AuroraCronJob> auroraCronJobProvider) {
- this.auroraCronJobProvider = checkNotNull(auroraCronJobProvider);
- }
-
- @Override
- public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
- checkState(AuroraCronJob.class.equals(bundle.getJobDetail().getJobClass()),
- "Quartz tried to run a type of job we don't know about: "
- + bundle.getJobDetail().getJobClass());
-
- return auroraCronJobProvider.get();
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImpl.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImpl.java
deleted file mode 100644
index 8a5f569..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImpl.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.inject.Inject;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-
-import org.apache.aurora.gen.CronCollisionPolicy;
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
-import org.apache.aurora.scheduler.storage.JobStore;
-import org.apache.aurora.scheduler.storage.Storage;
-import org.apache.aurora.scheduler.storage.Storage.MutateWork;
-import org.apache.aurora.scheduler.storage.Storage.Work;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.quartz.JobDetail;
-import org.quartz.JobKey;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.impl.matchers.GroupMatcher;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * NOTE: The source of truth for whether a cron job exists or not is always the JobStore. If state
- * somehow becomes inconsistent (i.e. a job key is scheduled for execution but its underlying
- * JobConfiguration does not exist in storage the execution of the job will log a warning and
- * exit).
- */
-class CronJobManagerImpl implements CronJobManager {
- private static final Logger LOG = Logger.getLogger(CronJobManagerImpl.class.getName());
-
- private final Storage storage;
- private final Scheduler scheduler;
- private final TimeZone timeZone;
-
- @Inject
- CronJobManagerImpl(Storage storage, Scheduler scheduler, TimeZone timeZone) {
- this.storage = checkNotNull(storage);
- this.scheduler = checkNotNull(scheduler);
- this.timeZone = checkNotNull(timeZone);
- }
-
- @Override
- public String getManagerKey() {
- return "CRON";
- }
-
- @Override
- public void startJobNow(final IJobKey jobKey) throws CronException {
- checkNotNull(jobKey);
-
- storage.weaklyConsistentRead(new Work<Void, CronException>() {
- @Override
- public Void apply(Storage.StoreProvider storeProvider) throws CronException {
- checkCronExists(jobKey, storeProvider.getJobStore());
- triggerJob(jobKey);
- return null;
- }
- });
- }
-
- private void triggerJob(IJobKey jobKey) throws CronException {
- try {
- scheduler.triggerJob(Quartz.jobKey(jobKey));
- } catch (SchedulerException e) {
- throw new CronException(e);
- }
- LOG.info(String.format("Triggered cron job for %s.", JobKeys.canonicalString(jobKey)));
- }
-
- private static void checkNoRunOverlap(SanitizedCronJob cronJob) throws CronException {
- // NOTE: We check at create and update instead of in SanitizedCronJob to allow existing jobs
- // but reject new ones.
- if (CronCollisionPolicy.RUN_OVERLAP.equals(cronJob.getCronCollisionPolicy())) {
- throw new CronException(
- "The RUN_OVERLAP collision policy has been removed (AURORA-38).");
- }
- }
-
- @Override
- public void updateJob(final SanitizedCronJob config) throws CronException {
- checkNotNull(config);
- checkNoRunOverlap(config);
-
- final IJobKey jobKey = config.getSanitizedConfig().getJobConfig().getKey();
- storage.write(new MutateWork.NoResult<CronException>() {
- @Override
- public void execute(Storage.MutableStoreProvider storeProvider) throws CronException {
- checkCronExists(jobKey, storeProvider.getJobStore());
-
- removeJob(jobKey, storeProvider.getJobStore());
- descheduleJob(jobKey);
- saveJob(config, storeProvider.getJobStore());
- scheduleJob(config.getCrontabEntry(), jobKey);
- }
- });
- }
-
- @Override
- public void createJob(final SanitizedCronJob cronJob) throws CronException {
- checkNotNull(cronJob);
- checkNoRunOverlap(cronJob);
-
- final IJobKey jobKey = cronJob.getSanitizedConfig().getJobConfig().getKey();
- storage.write(new MutateWork.NoResult<CronException>() {
- @Override
- protected void execute(Storage.MutableStoreProvider storeProvider) throws CronException {
- checkNotExists(jobKey, storeProvider.getJobStore());
-
- saveJob(cronJob, storeProvider.getJobStore());
- scheduleJob(cronJob.getCrontabEntry(), jobKey);
- }
- });
- }
-
- private void checkNotExists(IJobKey jobKey, JobStore jobStore) throws CronException {
- if (jobStore.fetchJob(getManagerKey(), jobKey).isPresent()) {
- throw new CronException(
- String.format("Job already exists for %s.", JobKeys.canonicalString(jobKey)));
- }
- }
-
- private void checkCronExists(IJobKey jobKey, JobStore jobStore) throws CronException {
- if (!jobStore.fetchJob(getManagerKey(), jobKey).isPresent()) {
- throw new CronException(
- String.format("No cron template found for %s.", JobKeys.canonicalString(jobKey)));
- }
- }
-
- private void removeJob(IJobKey jobKey, JobStore.Mutable jobStore) {
- jobStore.removeJob(jobKey);
- LOG.info(
- String.format("Deleted cron job %s from storage.", JobKeys.canonicalString(jobKey)));
- }
-
- private void saveJob(SanitizedCronJob cronJob, JobStore.Mutable jobStore) {
- IJobConfiguration config = cronJob.getSanitizedConfig().getJobConfig();
-
- jobStore.saveAcceptedJob(getManagerKey(), config);
- LOG.info(String.format(
- "Saved new cron job %s to storage.", JobKeys.canonicalString(config.getKey())));
- }
-
- // TODO(ksweeney): Consider exposing this in the interface and making caller responsible.
- void scheduleJob(CrontabEntry crontabEntry, IJobKey jobKey) throws CronException {
- try {
- scheduler.scheduleJob(
- Quartz.jobDetail(jobKey, AuroraCronJob.class),
- Quartz.cronTrigger(crontabEntry, timeZone));
- } catch (SchedulerException e) {
- throw new CronException(e);
- }
- LOG.info(String.format(
- "Scheduled job %s with schedule %s.", JobKeys.canonicalString(jobKey), crontabEntry));
- }
-
- @Override
- public Iterable<IJobConfiguration> getJobs() {
- // NOTE: no synchronization is needed here since we don't touch internal quartz state.
- return storage.consistentRead(new Work.Quiet<Iterable<IJobConfiguration>>() {
- @Override
- public Iterable<IJobConfiguration> apply(Storage.StoreProvider storeProvider) {
- return storeProvider.getJobStore().fetchJobs(getManagerKey());
- }
- });
- }
-
- @Override
- public boolean hasJob(final IJobKey jobKey) {
- checkNotNull(jobKey);
-
- return storage.consistentRead(new Work.Quiet<Boolean>() {
- @Override
- public Boolean apply(Storage.StoreProvider storeProvider) {
- return storeProvider.getJobStore().fetchJob(getManagerKey(), jobKey).isPresent();
- }
- });
- }
-
- @Override
- public boolean deleteJob(final IJobKey jobKey) {
- checkNotNull(jobKey);
-
- return storage.write(new MutateWork.Quiet<Boolean>() {
- @Override
- public Boolean apply(Storage.MutableStoreProvider storeProvider) {
- if (!hasJob(jobKey)) {
- return false;
- }
-
- removeJob(jobKey, storeProvider.getJobStore());
- descheduleJob(jobKey);
- return true;
- }
- });
- }
-
- private void descheduleJob(IJobKey jobKey) {
- String path = JobKeys.canonicalString(jobKey);
- try {
- // TODO(ksweeney): Consider interrupting the running job here.
- // There's a race here where an old running job could fail to find the old config. That's
- // fine given that the behavior of AuroraCronJob is to log an error and exit if it's unable
- // to find a job for its key.
- scheduler.deleteJob(Quartz.jobKey(jobKey));
- LOG.info("Successfully descheduled " + path + ".");
- } catch (SchedulerException e) {
- LOG.log(Level.WARNING, "Error when attempting to deschedule " + path + ": " + e, e);
- }
- }
-
- @Override
- public Map<IJobKey, CrontabEntry> getScheduledJobs() {
- // NOTE: no synchronization is needed here since this is just a dump of internal quartz state
- // for debugging.
- ImmutableMap.Builder<IJobKey, CrontabEntry> scheduledJobs = ImmutableMap.builder();
- try {
- for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.<JobKey>anyGroup())) {
- Optional<JobDetail> jobDetail = Optional.fromNullable(scheduler.getJobDetail(jobKey));
- if (jobDetail.isPresent()) {
- scheduledJobs.put(
- Quartz.auroraJobKey(jobKey), CrontabEntry.parse(jobDetail.get().getDescription()));
- }
- }
- } catch (SchedulerException e) {
- throw Throwables.propagate(e);
- }
- return scheduledJobs.build();
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronLifecycle.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronLifecycle.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronLifecycle.java
deleted file mode 100644
index 64fa068..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronLifecycle.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.inject.Inject;
-
-import com.google.common.eventbus.Subscribe;
-import com.google.common.util.concurrent.AbstractIdleService;
-import com.twitter.common.application.ShutdownRegistry;
-import com.twitter.common.base.Command;
-import com.twitter.common.stats.Stats;
-
-import org.apache.aurora.scheduler.configuration.ConfigurationManager;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
-import org.apache.aurora.scheduler.events.PubsubEvent;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.quartz.Scheduler;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Manager for startup and teardown of Quartz scheduler.
- */
-class CronLifecycle extends AbstractIdleService implements PubsubEvent.EventSubscriber {
- private static final Logger LOG = Logger.getLogger(CronLifecycle.class.getName());
-
- private static final AtomicInteger RUNNING_FLAG = Stats.exportInt("quartz_scheduler_running");
- private static final AtomicInteger LOADED_FLAG = Stats.exportInt("cron_jobs_loaded");
- private static final AtomicLong LAUNCH_FAILURES = Stats.exportLong("cron_job_launch_failures");
-
- private final Scheduler scheduler;
- private final ShutdownRegistry shutdownRegistry;
- private final CronJobManagerImpl cronJobManager;
-
- @Inject
- CronLifecycle(
- Scheduler scheduler,
- ShutdownRegistry shutdownRegistry,
- CronJobManagerImpl cronJobManager) {
-
- this.scheduler = checkNotNull(scheduler);
- this.shutdownRegistry = checkNotNull(shutdownRegistry);
- this.cronJobManager = checkNotNull(cronJobManager);
- }
-
- /**
- * Notifies the cronScheduler job manager that the scheduler is active, and job configurations
- * are ready to load.
- *
- * @param schedulerActive Event.
- */
- @Subscribe
- public void schedulerActive(PubsubEvent.SchedulerActive schedulerActive) {
- startAsync();
- shutdownRegistry.addAction(new Command() {
- @Override
- public void execute() {
- CronLifecycle.this.stopAsync().awaitTerminated();
- }
- });
- awaitRunning();
- }
-
- @Override
- protected void startUp() throws Exception {
- LOG.info("Starting Quartz cron scheduler" + scheduler.getSchedulerName() + ".");
- scheduler.start();
- RUNNING_FLAG.set(1);
-
- // TODO(ksweeney): Refactor the interface - we really only need the job keys here.
- for (IJobConfiguration job : cronJobManager.getJobs()) {
- try {
- SanitizedCronJob cronJob = SanitizedCronJob.fromUnsanitized(job);
- cronJobManager.scheduleJob(
- cronJob.getCrontabEntry(),
- cronJob.getSanitizedConfig().getJobConfig().getKey());
- } catch (CronException | ConfigurationManager.TaskDescriptionException e) {
- logLaunchFailure(job, e);
- }
- }
- LOADED_FLAG.set(1);
- }
-
- private void logLaunchFailure(IJobConfiguration job, Exception e) {
- LAUNCH_FAILURES.incrementAndGet();
- LOG.log(Level.SEVERE, "Scheduling failed for recovered job " + job, e);
- }
-
- @Override
- protected void shutDown() throws Exception {
- LOG.info("Shutting down Quartz cron scheduler.");
- scheduler.shutdown();
- RUNNING_FLAG.set(0);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronModule.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronModule.java
deleted file mode 100644
index 6934828..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronModule.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.TimeZone;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Logger;
-
-import javax.inject.Singleton;
-
-import com.google.common.base.Throwables;
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-import com.twitter.common.args.Arg;
-import com.twitter.common.args.CmdLine;
-import com.twitter.common.quantity.Amount;
-import com.twitter.common.quantity.Time;
-import com.twitter.common.util.BackoffHelper;
-
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.cron.CronPredictor;
-import org.apache.aurora.scheduler.cron.CronScheduler;
-import org.apache.aurora.scheduler.events.PubsubEventModule;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.impl.DirectSchedulerFactory;
-import org.quartz.simpl.RAMJobStore;
-import org.quartz.simpl.SimpleThreadPool;
-
-/**
- * Provides a {@link CronJobManager} with a Quartz backend. While Quartz itself supports
- * persistence, the scheduler exposed by this module does not persist any state - it simply
- * creates tasks from a {@link org.apache.aurora.gen.JobConfiguration} template on a cron-style
- * schedule.
- */
-public class CronModule extends AbstractModule {
- private static final Logger LOG = Logger.getLogger(CronModule.class.getName());
-
- @CmdLine(name = "cron_scheduler_num_threads",
- help = "Number of threads to use for the cron scheduler thread pool.")
- private static final Arg<Integer> NUM_THREADS = Arg.create(100);
-
- @CmdLine(name = "cron_timezone", help = "TimeZone to use for cron predictions.")
- private static final Arg<String> CRON_TIMEZONE = Arg.create("GMT");
-
- @CmdLine(name = "cron_start_initial_backoff", help =
- "Initial backoff delay while waiting for a previous cron run to be killed.")
- public static final Arg<Amount<Long, Time>> CRON_START_INITIAL_BACKOFF =
- Arg.create(Amount.of(1L, Time.SECONDS));
-
- @CmdLine(name = "cron_start_max_backoff", help =
- "Max backoff delay while waiting for a previous cron run to be killed.")
- public static final Arg<Amount<Long, Time>> CRON_START_MAX_BACKOFF =
- Arg.create(Amount.of(1L, Time.MINUTES));
-
- // Global per-JVM ID number generator for the provided Quartz Scheduler.
- private static final AtomicLong ID_GENERATOR = new AtomicLong();
-
- @Override
- protected void configure() {
- bind(CronPredictor.class).to(CronPredictorImpl.class);
- bind(CronPredictorImpl.class).in(Singleton.class);
-
- bind(CronJobManager.class).to(CronJobManagerImpl.class);
- bind(CronJobManagerImpl.class).in(Singleton.class);
-
- bind(CronScheduler.class).to(CronSchedulerImpl.class);
- bind(CronSchedulerImpl.class).in(Singleton.class);
-
- bind(AuroraCronJobFactory.class).in(Singleton.class);
-
- bind(AuroraCronJob.class).in(Singleton.class);
- bind(AuroraCronJob.Config.class).toInstance(new AuroraCronJob.Config(
- new BackoffHelper(CRON_START_INITIAL_BACKOFF.get(), CRON_START_MAX_BACKOFF.get())));
-
- bind(CronLifecycle.class).in(Singleton.class);
- PubsubEventModule.bindSubscriber(binder(), CronLifecycle.class);
- }
-
- @Provides
- private TimeZone provideTimeZone() {
- TimeZone timeZone = TimeZone.getTimeZone(CRON_TIMEZONE.get());
- TimeZone systemTimeZone = TimeZone.getDefault();
- if (!timeZone.equals(systemTimeZone)) {
- LOG.warning("Cron schedules are configured to fire according to timezone "
- + timeZone.getDisplayName()
- + " but system timezone is set to "
- + systemTimeZone.getDisplayName());
- }
- return timeZone;
- }
-
- /*
- * NOTE: Quartz implements DirectSchedulerFactory as a mutable global singleton in a static
- * variable. While the Scheduler instances it produces are independent we synchronize here to
- * avoid an initialization race across injectors. In practice this only shows up during testing;
- * production Aurora instances will only have one object graph at a time.
- */
- @Provides
- @Singleton
- private static synchronized Scheduler provideScheduler(AuroraCronJobFactory jobFactory) {
- SimpleThreadPool threadPool = new SimpleThreadPool(NUM_THREADS.get(), Thread.NORM_PRIORITY);
- threadPool.setMakeThreadsDaemons(true);
-
- DirectSchedulerFactory schedulerFactory = DirectSchedulerFactory.getInstance();
- String schedulerName = "aurora-cron-" + ID_GENERATOR.incrementAndGet();
- try {
- schedulerFactory.createScheduler(schedulerName, schedulerName, threadPool, new RAMJobStore());
- Scheduler scheduler = schedulerFactory.getScheduler(schedulerName);
- scheduler.setJobFactory(jobFactory);
- return scheduler;
- } catch (SchedulerException e) {
- LOG.severe("Error initializing Quartz cron scheduler: " + e);
- throw Throwables.propagate(e);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImpl.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImpl.java
deleted file mode 100644
index fb24c28..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImpl.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.Date;
-import java.util.TimeZone;
-
-import javax.inject.Inject;
-
-import com.twitter.common.util.Clock;
-
-import org.apache.aurora.scheduler.cron.CronPredictor;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.quartz.CronExpression;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-class CronPredictorImpl implements CronPredictor {
- private final Clock clock;
- private final TimeZone timeZone;
-
- @Inject
- CronPredictorImpl(Clock clock, TimeZone timeZone) {
- this.clock = checkNotNull(clock);
- this.timeZone = checkNotNull(timeZone);
- }
-
- @Override
- public Date predictNextRun(CrontabEntry schedule) {
- CronExpression cronExpression = Quartz.cronExpression(schedule, timeZone);
- return cronExpression.getNextValidTimeAfter(new Date(clock.nowMillis()));
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl.java
deleted file mode 100644
index 3bef22d..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.inject.Inject;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Iterables;
-import com.twitter.common.base.Function;
-
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.cron.CronScheduler;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.quartz.CronTrigger;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import static org.apache.aurora.scheduler.cron.quartz.Quartz.jobKey;
-
-class CronSchedulerImpl implements CronScheduler {
- private static final Logger LOG = Logger.getLogger(CronSchedulerImpl.class.getName());
-
- private final Scheduler scheduler;
-
- @Inject
- CronSchedulerImpl(Scheduler scheduler) {
- this.scheduler = checkNotNull(scheduler);
- }
-
- @Override
- public Optional<CrontabEntry> getSchedule(IJobKey jobKey) throws IllegalStateException {
- checkNotNull(jobKey);
-
- try {
- return Optional.of(Iterables.getOnlyElement(
- FluentIterable.from(scheduler.getTriggersOfJob(jobKey(jobKey)))
- .filter(CronTrigger.class)
- .transform(new Function<CronTrigger, CrontabEntry>() {
- @Override
- public CrontabEntry apply(CronTrigger trigger) {
- return Quartz.crontabEntry(trigger);
- }
- })));
- } catch (SchedulerException e) {
- LOG.log(Level.SEVERE,
- "Error reading job " + JobKeys.canonicalString(jobKey) + " cronExpression Quartz: " + e,
- e);
- return Optional.absent();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/quartz/Quartz.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/quartz/Quartz.java b/src/main/java/org/apache/aurora/scheduler/cron/quartz/Quartz.java
deleted file mode 100644
index 63aaade..0000000
--- a/src/main/java/org/apache/aurora/scheduler/cron/quartz/Quartz.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.text.ParseException;
-import java.util.List;
-import java.util.TimeZone;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ContiguousSet;
-import com.google.common.collect.DiscreteDomain;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Range;
-
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.quartz.CronExpression;
-import org.quartz.CronScheduleBuilder;
-import org.quartz.CronTrigger;
-import org.quartz.Job;
-import org.quartz.JobBuilder;
-import org.quartz.JobDetail;
-import org.quartz.JobKey;
-import org.quartz.TriggerBuilder;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Utilities for converting Aurora datatypes to Quartz datatypes.
- */
-final class Quartz {
- private Quartz() {
- // Utility class.
- }
-
- /**
- * Convert an Aurora CrontabEntry to a Quartz CronExpression.
- */
- static CronExpression cronExpression(CrontabEntry entry, TimeZone timeZone) {
- String dayOfMonth;
- if (entry.hasWildcardDayOfMonth()) {
- dayOfMonth = "?"; // special quartz token meaning "don't care"
- } else {
- dayOfMonth = entry.getDayOfMonthAsString();
- }
- String dayOfWeek;
- if (entry.hasWildcardDayOfWeek() && !entry.hasWildcardDayOfMonth()) {
- dayOfWeek = "?";
- } else {
- List<Integer> daysOfWeek = Lists.newArrayList();
- for (Range<Integer> range : entry.getDayOfWeek().asRanges()) {
- for (int i : ContiguousSet.create(range, DiscreteDomain.integers())) {
- daysOfWeek.add(i + 1); // Quartz has an off-by-one with what the "standard" defines.
- }
- }
- dayOfWeek = Joiner.on(",").join(daysOfWeek);
- }
-
- String rawCronExpresion = Joiner.on(" ").join(
- "0",
- entry.getMinuteAsString(),
- entry.getHourAsString(),
- dayOfMonth,
- entry.getMonthAsString(),
- dayOfWeek);
- CronExpression cronExpression;
- try {
- cronExpression = new CronExpression(rawCronExpresion);
- } catch (ParseException e) {
- throw Throwables.propagate(e);
- }
- cronExpression.setTimeZone(timeZone);
- return cronExpression;
- }
-
- /**
- * Convert a Quartz JobKey to an Aurora IJobKey.
- */
- static IJobKey auroraJobKey(org.quartz.JobKey jobKey) {
- return JobKeys.parse(jobKey.getName());
- }
-
- /**
- * Convert an Aurora IJobKey to a Quartz JobKey.
- */
- static JobKey jobKey(IJobKey jobKey) {
- return JobKey.jobKey(JobKeys.canonicalString(jobKey));
- }
-
- static CronTrigger cronTrigger(CrontabEntry schedule, TimeZone timeZone) {
- return TriggerBuilder.newTrigger()
- .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression(schedule, timeZone)))
- .withDescription(schedule.toString())
- .build();
- }
-
- static JobDetail jobDetail(IJobKey jobKey, Class<? extends Job> jobClass) {
- checkNotNull(jobKey);
- checkNotNull(jobClass);
-
- return JobBuilder.newJob(jobClass)
- .withIdentity(jobKey(jobKey))
- .build();
- }
-
- static CrontabEntry crontabEntry(CronTrigger cronTrigger) {
- return CrontabEntry.parse(cronTrigger.getDescription());
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/cron/testing/AbstractCronIT.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/cron/testing/AbstractCronIT.java b/src/main/java/org/apache/aurora/scheduler/cron/testing/AbstractCronIT.java
new file mode 100644
index 0000000..61b01d2
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/cron/testing/AbstractCronIT.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright 2013 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.cron.testing;
+
+import java.io.InputStreamReader;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.twitter.common.util.Clock;
+import com.twitter.common.util.testing.FakeClock;
+
+import org.apache.aurora.scheduler.cron.CronPredictor;
+import org.apache.aurora.scheduler.cron.CronScheduler;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Abstract test to verify conformance with the {@link CronScheduler} interface.
+ */
+public abstract class AbstractCronIT {
+ private static final String WILDCARD_SCHEDULE = "* * * * *";
+
+ /**
+ * Child should return an instance of the {@link CronScheduler} test under test here.
+ */
+ protected abstract CronScheduler makeCronScheduler() throws Exception;
+
+ /**
+ * Child should return an instance of the {@link CronPredictor} under test here.
+ *
+ * @param clock The clock the predictor should use.
+ */
+ protected abstract CronPredictor makeCronPredictor(Clock clock) throws Exception;
+
+ @Test
+ public void testCronSchedulerLifecycle() throws Exception {
+ CronScheduler scheduler = makeCronScheduler();
+
+ scheduler.startAsync().awaitRunning();
+ final CountDownLatch cronRan = new CountDownLatch(1);
+ scheduler.schedule(WILDCARD_SCHEDULE, new Runnable() {
+ @Override public void run() {
+ cronRan.countDown();
+ }
+ });
+ cronRan.await();
+ scheduler.stopAsync().awaitTerminated();
+ }
+
+ @Test
+ public void testCronPredictorConforms() throws Exception {
+ FakeClock clock = new FakeClock();
+ CronPredictor cronPredictor = makeCronPredictor(clock);
+
+ for (TriggerPrediction triggerPrediction : getExpectedTriggerPredictions()) {
+ List<Long> results = Lists.newArrayList();
+ clock.setNowMillis(0);
+ for (int i = 0; i < triggerPrediction.getTriggerTimes().size(); i++) {
+ Date nextTriggerTime = cronPredictor.predictNextRun(triggerPrediction.getSchedule());
+ results.add(nextTriggerTime.getTime());
+ clock.setNowMillis(nextTriggerTime.getTime());
+ }
+ assertEquals("Cron schedule "
+ + triggerPrediction.getSchedule()
+ + " should have have predicted trigger times "
+ + triggerPrediction.getTriggerTimes()
+ + " but predicted "
+ + results
+ + " instead.", triggerPrediction.getTriggerTimes(), results);
+ }
+ }
+
+ @Test
+ public void testCronScheduleValidatorAcceptsValidSchedules() throws Exception {
+ CronScheduler cron = makeCronScheduler();
+
+ for (TriggerPrediction triggerPrediction : getExpectedTriggerPredictions()) {
+ assertTrue("Cron schedule " + triggerPrediction.getSchedule() + " should pass validation.",
+ cron.isValidSchedule(triggerPrediction.getSchedule()));
+ }
+ }
+
+ private static List<TriggerPrediction> getExpectedTriggerPredictions() {
+ return new Gson()
+ .fromJson(
+ new InputStreamReader(
+ AbstractCronIT.class.getResourceAsStream("cron-schedule-predictions.json")),
+ new TypeToken<List<TriggerPrediction>>() { }.getType());
+ }
+
+ /**
+ * A schedule and the expected iteratively-applied prediction results.
+ */
+ public static class TriggerPrediction {
+ private String schedule;
+ private List<Long> triggerTimes;
+
+ private TriggerPrediction() {
+ // GSON constructor.
+ }
+
+ public TriggerPrediction(String schedule, List<Long> triggerTimes) {
+ this.schedule = schedule;
+ this.triggerTimes = triggerTimes;
+ }
+
+ public String getSchedule() {
+ return schedule;
+ }
+
+ public List<Long> getTriggerTimes() {
+ return ImmutableList.copyOf(triggerTimes);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/http/Cron.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/http/Cron.java b/src/main/java/org/apache/aurora/scheduler/http/Cron.java
index d8c44f8..80a398a 100644
--- a/src/main/java/org/apache/aurora/scheduler/http/Cron.java
+++ b/src/main/java/org/apache/aurora/scheduler/http/Cron.java
@@ -26,7 +26,7 @@ import javax.ws.rs.core.Response;
import com.google.common.collect.ImmutableMap;
-import org.apache.aurora.scheduler.cron.CronJobManager;
+import org.apache.aurora.scheduler.state.CronJobManager;
/**
* HTTP interface to dump state of the internal cron scheduler.
@@ -50,6 +50,7 @@ public class Cron {
public Response dumpContents() {
Map<String, Object> response = ImmutableMap.<String, Object>builder()
.put("scheduled", cronManager.getScheduledJobs())
+ .put("pending", cronManager.getPendingRuns())
.build();
return Response.ok(response).build();
[4/5] Revert "AURORA-132: Cron system based on Quartz"
Posted by ke...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java b/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
index 6d76f60..9831012 100644
--- a/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
+++ b/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
@@ -39,8 +39,8 @@ import com.twitter.common.net.pool.DynamicHostSet;
import com.twitter.common.net.pool.DynamicHostSet.MonitorException;
import com.twitter.thrift.ServiceInstance;
-import org.apache.aurora.scheduler.cron.CronJobManager;
import org.apache.aurora.scheduler.quota.QuotaManager;
+import org.apache.aurora.scheduler.state.CronJobManager;
import org.apache.aurora.scheduler.state.SchedulerCore;
import org.apache.aurora.scheduler.storage.entities.IServerInfo;
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/http/StructDump.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/http/StructDump.java b/src/main/java/org/apache/aurora/scheduler/http/StructDump.java
index 823668f..efea75f 100644
--- a/src/main/java/org/apache/aurora/scheduler/http/StructDump.java
+++ b/src/main/java/org/apache/aurora/scheduler/http/StructDump.java
@@ -25,6 +25,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.twitter.common.base.Closure;
import com.twitter.common.thrift.Util;
@@ -33,7 +34,7 @@ import org.antlr.stringtemplate.StringTemplate;
import org.apache.aurora.gen.JobConfiguration;
import org.apache.aurora.scheduler.base.JobKeys;
import org.apache.aurora.scheduler.base.Query;
-import org.apache.aurora.scheduler.cron.CronJobManager;
+import org.apache.aurora.scheduler.state.CronJobManager;
import org.apache.aurora.scheduler.storage.Storage;
import org.apache.aurora.scheduler.storage.Storage.StoreProvider;
import org.apache.aurora.scheduler.storage.Storage.Work;
@@ -42,8 +43,6 @@ import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
import org.apache.aurora.scheduler.storage.entities.IJobKey;
import org.apache.thrift.TBase;
-import static com.google.common.base.Preconditions.checkNotNull;
-
/**
* Servlet that prints out the raw configuration for a specified struct.
*/
@@ -51,13 +50,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class StructDump extends JerseyTemplateServlet {
private final Storage storage;
- private final CronJobManager cronJobManager;
@Inject
- public StructDump(Storage storage, CronJobManager cronJobManager) {
+ public StructDump(Storage storage) {
super("structdump");
- this.storage = checkNotNull(storage);
- this.cronJobManager = checkNotNull(cronJobManager);
+ this.storage = Preconditions.checkNotNull(storage);
}
private static final String USAGE =
@@ -109,11 +106,11 @@ public class StructDump extends JerseyTemplateServlet {
@PathParam("job") final String job) {
final IJobKey jobKey = JobKeys.from(role, environment, job);
- return dumpEntity("Cron job " + JobKeys.canonicalString(jobKey),
+ return dumpEntity("Cron job " + JobKeys.toPath(jobKey),
new Work.Quiet<Optional<? extends TBase<?, ?>>>() {
@Override
public Optional<JobConfiguration> apply(StoreProvider storeProvider) {
- return storeProvider.getJobStore().fetchJob(cronJobManager.getManagerKey(), jobKey)
+ return storeProvider.getJobStore().fetchJob(CronJobManager.MANAGER_KEY, jobKey)
.transform(IJobConfiguration.TO_BUILDER);
}
});
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/state/CronJobManager.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/state/CronJobManager.java b/src/main/java/org/apache/aurora/scheduler/state/CronJobManager.java
new file mode 100644
index 0000000..4bd190c
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/state/CronJobManager.java
@@ -0,0 +1,484 @@
+/**
+ * Copyright 2013 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.state;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.eventbus.Subscribe;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.twitter.common.application.ShutdownRegistry;
+import com.twitter.common.args.Arg;
+import com.twitter.common.args.CmdLine;
+import com.twitter.common.base.Command;
+import com.twitter.common.base.Supplier;
+import com.twitter.common.quantity.Amount;
+import com.twitter.common.quantity.Time;
+import com.twitter.common.stats.Stats;
+import com.twitter.common.util.BackoffHelper;
+
+import org.apache.aurora.gen.CronCollisionPolicy;
+import org.apache.aurora.gen.ScheduleStatus;
+import org.apache.aurora.scheduler.base.JobKeys;
+import org.apache.aurora.scheduler.base.Query;
+import org.apache.aurora.scheduler.base.ScheduleException;
+import org.apache.aurora.scheduler.base.Tasks;
+import org.apache.aurora.scheduler.configuration.ConfigurationManager.TaskDescriptionException;
+import org.apache.aurora.scheduler.configuration.SanitizedConfiguration;
+import org.apache.aurora.scheduler.cron.CronException;
+import org.apache.aurora.scheduler.cron.CronScheduler;
+import org.apache.aurora.scheduler.events.PubsubEvent.EventSubscriber;
+import org.apache.aurora.scheduler.events.PubsubEvent.SchedulerActive;
+import org.apache.aurora.scheduler.storage.Storage;
+import org.apache.aurora.scheduler.storage.Storage.MutateWork;
+import org.apache.aurora.scheduler.storage.Storage.Work;
+import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
+import org.apache.aurora.scheduler.storage.entities.IJobKey;
+import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
+import org.apache.commons.lang.StringUtils;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import static org.apache.aurora.gen.ScheduleStatus.KILLING;
+
+/**
+ * A job scheduler that receives jobs that should be run periodically on a cron schedule.
+ */
+public class CronJobManager implements EventSubscriber {
+
+ public static final String MANAGER_KEY = "CRON";
+
+ @VisibleForTesting
+ static final Optional<String> KILL_AUDIT_MESSAGE = Optional.of("Killed by cron");
+
+ private static final Logger LOG = Logger.getLogger(CronJobManager.class.getName());
+
+ @CmdLine(name = "cron_start_initial_backoff", help =
+ "Initial backoff delay while waiting for a previous cron run to start.")
+ private static final Arg<Amount<Long, Time>> CRON_START_INITIAL_BACKOFF =
+ Arg.create(Amount.of(1L, Time.SECONDS));
+
+ @CmdLine(name = "cron_start_max_backoff", help =
+ "Max backoff delay while waiting for a previous cron run to start.")
+ private static final Arg<Amount<Long, Time>> CRON_START_MAX_BACKOFF =
+ Arg.create(Amount.of(1L, Time.MINUTES));
+
+ private final AtomicLong cronJobsTriggered = Stats.exportLong("cron_jobs_triggered");
+ private final AtomicLong cronJobLaunchFailures = Stats.exportLong("cron_job_launch_failures");
+
+ // Maps from the unique job identifier to the unique identifier used internally by the cron
+ // scheduler.
+ private final Map<IJobKey, String> scheduledJobs =
+ Collections.synchronizedMap(Maps.<IJobKey, String>newHashMap());
+
+ // Prevents runs from dogpiling while waiting for a run to transition out of the KILLING state.
+ // This is necessary because killing a job (if dictated by cron collision policy) is an
+ // asynchronous operation.
+ private final Map<IJobKey, SanitizedConfiguration> pendingRuns =
+ Collections.synchronizedMap(Maps.<IJobKey, SanitizedConfiguration>newHashMap());
+
+ private final StateManager stateManager;
+ private final Storage storage;
+ private final CronScheduler cron;
+ private final ShutdownRegistry shutdownRegistry;
+ private final BackoffHelper delayedStartBackoff;
+ private final Executor delayedRunExecutor;
+
+ @Inject
+ CronJobManager(
+ StateManager stateManager,
+ Storage storage,
+ CronScheduler cron,
+ ShutdownRegistry shutdownRegistry) {
+
+ this(
+ stateManager,
+ storage,
+ cron,
+ shutdownRegistry,
+ Executors.newCachedThreadPool(
+ new ThreadFactoryBuilder().setDaemon(true).setNameFormat("CronDelay-%d").build()));
+ }
+
+ @VisibleForTesting
+ CronJobManager(
+ StateManager stateManager,
+ Storage storage,
+ CronScheduler cron,
+ ShutdownRegistry shutdownRegistry,
+ Executor delayedRunExecutor) {
+
+ this.stateManager = checkNotNull(stateManager);
+ this.storage = checkNotNull(storage);
+ this.cron = checkNotNull(cron);
+ this.shutdownRegistry = checkNotNull(shutdownRegistry);
+ this.delayedStartBackoff =
+ new BackoffHelper(CRON_START_INITIAL_BACKOFF.get(), CRON_START_MAX_BACKOFF.get());
+ this.delayedRunExecutor = checkNotNull(delayedRunExecutor);
+
+ Stats.exportSize("cron_num_pending_runs", pendingRuns);
+ }
+
+ private void mapScheduledJob(SanitizedCronJob cronJob) throws ScheduleException {
+ IJobKey jobKey = cronJob.config.getJobConfig().getKey();
+ synchronized (scheduledJobs) {
+ Preconditions.checkState(
+ !scheduledJobs.containsKey(jobKey),
+ "Illegal state - cron schedule already exists for " + JobKeys.toPath(jobKey));
+ scheduledJobs.put(jobKey, scheduleJob(cronJob));
+ }
+ }
+
+ /**
+ * Notifies the cron job manager that the scheduler is active, and job configurations are ready to
+ * load.
+ *
+ * @param schedulerActive Event.
+ */
+ @Subscribe
+ public void schedulerActive(SchedulerActive schedulerActive) {
+ cron.startAsync().awaitRunning();
+ shutdownRegistry.addAction(new Command() {
+ @Override
+ public void execute() {
+ // NOTE: We don't know ahead-of-time which thread will execute the shutdown command,
+ // so we shouldn't block here.
+ cron.stopAsync();
+ }
+ });
+
+ Iterable<IJobConfiguration> crons =
+ storage.consistentRead(new Work.Quiet<Iterable<IJobConfiguration>>() {
+ @Override
+ public Iterable<IJobConfiguration> apply(Storage.StoreProvider storeProvider) {
+ return storeProvider.getJobStore().fetchJobs(MANAGER_KEY);
+ }
+ });
+
+ for (IJobConfiguration job : crons) {
+ try {
+ mapScheduledJob(new SanitizedCronJob(job, cron));
+ } catch (ScheduleException | TaskDescriptionException e) {
+ logLaunchFailure(job, e);
+ }
+ }
+ }
+
+ private void logLaunchFailure(IJobConfiguration job, Exception e) {
+ cronJobLaunchFailures.incrementAndGet();
+ LOG.log(Level.SEVERE, "Scheduling failed for recovered job " + job, e);
+ }
+
+ /**
+ * Triggers execution of a job.
+ *
+ * @param jobKey Key of the job to start.
+ * @throws ScheduleException If the job could not be started with the cron system.
+ * @throws TaskDescriptionException If the stored job associated with {@code jobKey} has field
+ * validation problems.
+ */
+ public void startJobNow(IJobKey jobKey) throws TaskDescriptionException, ScheduleException {
+ Optional<IJobConfiguration> jobConfig = fetchJob(jobKey);
+ if (!jobConfig.isPresent()) {
+ throw new ScheduleException("Cron job does not exist for " + JobKeys.toPath(jobKey));
+ }
+
+ cronTriggered(new SanitizedCronJob(jobConfig.get(), cron));
+ }
+
+ private void delayedRun(final Query.Builder query, final SanitizedConfiguration config) {
+ IJobConfiguration job = config.getJobConfig();
+ final String jobPath = JobKeys.toPath(job);
+ final IJobKey jobKey = job.getKey();
+ LOG.info("Waiting for job to terminate before launching cron job " + jobPath);
+ if (pendingRuns.put(jobKey, config) == null) {
+ LOG.info("Launching a task to wait for job to finish: " + jobPath);
+ // There was no run already pending for this job, launch a task to delay launch until the
+ // existing run has terminated.
+ delayedRunExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ runWhenTerminated(query, jobKey);
+ }
+ });
+ }
+ }
+
+ private void runWhenTerminated(final Query.Builder query, final IJobKey jobKey) {
+ try {
+ delayedStartBackoff.doUntilSuccess(new Supplier<Boolean>() {
+ @Override
+ public Boolean get() {
+ if (Storage.Util.consistentFetchTasks(storage, query).isEmpty()) {
+ LOG.info("Initiating delayed launch of cron " + jobKey);
+ SanitizedConfiguration config = pendingRuns.remove(jobKey);
+ checkNotNull(config, "Failed to fetch job for delayed run of " + jobKey);
+ LOG.info("Launching " + config.getTaskConfigs().size() + " tasks.");
+ stateManager.insertPendingTasks(config.getTaskConfigs());
+ return true;
+ } else {
+ LOG.info("Not yet safe to run cron " + jobKey);
+ return false;
+ }
+ }
+ });
+ } catch (InterruptedException e) {
+ LOG.log(Level.WARNING, "Interrupted while trying to launch cron " + jobKey, e);
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ private void killActiveTasks(Set<String> taskIds) {
+ if (taskIds.isEmpty()) {
+ return;
+ }
+
+ for (String taskId : taskIds) {
+ stateManager.changeState(
+ taskId,
+ Optional.<ScheduleStatus>absent(),
+ KILLING,
+ KILL_AUDIT_MESSAGE);
+ }
+ }
+
+ public static CronCollisionPolicy orDefault(@Nullable CronCollisionPolicy policy) {
+ return Optional.fromNullable(policy).or(CronCollisionPolicy.KILL_EXISTING);
+ }
+
+ /**
+ * Triggers execution of a cron job, depending on the cron collision policy for the job.
+ *
+ * @param cronJob The job to be triggered.
+ */
+ private void cronTriggered(SanitizedCronJob cronJob) {
+ final SanitizedConfiguration config = cronJob.config;
+ final IJobConfiguration job = config.getJobConfig();
+ LOG.info(String.format("Cron triggered for %s at %s with policy %s",
+ JobKeys.toPath(job), new Date(), job.getCronCollisionPolicy()));
+ cronJobsTriggered.incrementAndGet();
+
+ storage.write(new MutateWork.NoResult.Quiet() {
+ @Override protected void execute(Storage.MutableStoreProvider storeProvider) {
+ ImmutableMap.Builder<Integer, ITaskConfig> builder = ImmutableMap.builder();
+ Query.Builder activeQuery = Query.jobScoped(job.getKey()).active();
+ Set<String> activeTasks = Tasks.ids(storeProvider.getTaskStore().fetchTasks(activeQuery));
+
+ if (activeTasks.isEmpty()) {
+ builder.putAll(config.getTaskConfigs());
+ } else {
+ switch (orDefault(job.getCronCollisionPolicy())) {
+ case KILL_EXISTING:
+ killActiveTasks(activeTasks);
+ delayedRun(activeQuery, config);
+ break;
+
+ case CANCEL_NEW:
+ break;
+
+ case RUN_OVERLAP:
+ LOG.severe(String.format(
+ "Ignoring trigger for job %s with deprecated collision"
+ + "policy RUN_OVERLAP due to unterminated active tasks.",
+ JobKeys.toPath(job)));
+ break;
+
+ default:
+ LOG.severe("Unrecognized cron collision policy: " + job.getCronCollisionPolicy());
+ }
+ }
+
+ Map<Integer, ITaskConfig> newTasks = builder.build();
+ if (!newTasks.isEmpty()) {
+ stateManager.insertPendingTasks(newTasks);
+ }
+ }
+ });
+ }
+
+ /**
+ * Updates (re-schedules) the existing cron job.
+ *
+ * @param config New job configuration to update to.
+ * @throws ScheduleException If non-cron job confuration provided.
+ */
+ public void updateJob(SanitizedConfiguration config) throws ScheduleException {
+ IJobConfiguration job = config.getJobConfig();
+ if (!hasCronSchedule(job)) {
+ throw new ScheduleException("A cron job may not be updated to a non-cron job.");
+ }
+ String key = scheduledJobs.remove(job.getKey());
+ if (key == null) {
+ throw new ScheduleException(
+ "No cron template found for the given key: " + JobKeys.toPath(job));
+ }
+ cron.deschedule(key);
+ checkArgument(receiveJob(config));
+ }
+
+ private static boolean hasCronSchedule(IJobConfiguration job) {
+ checkNotNull(job);
+ return !StringUtils.isEmpty(job.getCronSchedule());
+ }
+
+ public boolean receiveJob(SanitizedConfiguration config) throws ScheduleException {
+ final IJobConfiguration job = config.getJobConfig();
+ if (!hasCronSchedule(job)) {
+ return false;
+ }
+
+ if (CronCollisionPolicy.RUN_OVERLAP.equals(job.getCronCollisionPolicy())) {
+ throw new ScheduleException(
+ "The RUN_OVERLAP collision policy has been removed (AURORA-38).");
+ }
+
+ SanitizedCronJob cronJob = new SanitizedCronJob(config, cron);
+ storage.write(new MutateWork.NoResult.Quiet() {
+ @Override
+ protected void execute(Storage.MutableStoreProvider storeProvider) {
+ storeProvider.getJobStore().saveAcceptedJob(MANAGER_KEY, job);
+ }
+ });
+ mapScheduledJob(cronJob);
+
+ return true;
+ }
+
+ private String scheduleJob(final SanitizedCronJob cronJob) throws ScheduleException {
+ IJobConfiguration job = cronJob.config.getJobConfig();
+ final String jobPath = JobKeys.toPath(job);
+ LOG.info(String.format("Scheduling cron job %s: %s", jobPath, job.getCronSchedule()));
+ try {
+ return cron.schedule(job.getCronSchedule(), new Runnable() {
+ @Override
+ public void run() {
+ // TODO(William Farner): May want to record information about job runs.
+ LOG.info("Running cron job: " + jobPath);
+ cronTriggered(cronJob);
+ }
+ });
+ } catch (CronException e) {
+ throw new ScheduleException("Failed to schedule cron job: " + e.getMessage(), e);
+ }
+ }
+
+ public Iterable<IJobConfiguration> getJobs() {
+ return storage.consistentRead(new Work.Quiet<Iterable<IJobConfiguration>>() {
+ @Override
+ public Iterable<IJobConfiguration> apply(Storage.StoreProvider storeProvider) {
+ return storeProvider.getJobStore().fetchJobs(MANAGER_KEY);
+ }
+ });
+ }
+
+ public boolean hasJob(IJobKey jobKey) {
+ return fetchJob(jobKey).isPresent();
+ }
+
+ private Optional<IJobConfiguration> fetchJob(final IJobKey jobKey) {
+ checkNotNull(jobKey);
+ return storage.consistentRead(new Work.Quiet<Optional<IJobConfiguration>>() {
+ @Override
+ public Optional<IJobConfiguration> apply(Storage.StoreProvider storeProvider) {
+ return storeProvider.getJobStore().fetchJob(MANAGER_KEY, jobKey);
+ }
+ });
+ }
+
+ public boolean deleteJob(final IJobKey jobKey) {
+ Optional<IJobConfiguration> job = fetchJob(jobKey);
+ if (!job.isPresent()) {
+ return false;
+ }
+
+ String scheduledJobKey = scheduledJobs.remove(jobKey);
+ if (scheduledJobKey != null) {
+ cron.deschedule(scheduledJobKey);
+ storage.write(new MutateWork.NoResult.Quiet() {
+ @Override
+ protected void execute(Storage.MutableStoreProvider storeProvider) {
+ storeProvider.getJobStore().removeJob(jobKey);
+ }
+ });
+ LOG.info("Successfully deleted cron job " + jobKey);
+ }
+ return true;
+ }
+
+ private final Function<String, String> keyToSchedule = new Function<String, String>() {
+ @Override
+ public String apply(String key) {
+ return cron.getSchedule(key).or("Not found.");
+ }
+ };
+
+ public Map<IJobKey, String> getScheduledJobs() {
+ synchronized (scheduledJobs) {
+ return ImmutableMap.copyOf(Maps.transformValues(scheduledJobs, keyToSchedule));
+ }
+ }
+
+ public Set<IJobKey> getPendingRuns() {
+ synchronized (pendingRuns) {
+ return ImmutableSet.copyOf(pendingRuns.keySet());
+ }
+ }
+
+ /**
+ * Used by functions that expect field validation before being called.
+ */
+ private static class SanitizedCronJob {
+ private final SanitizedConfiguration config;
+
+ SanitizedCronJob(IJobConfiguration unsanitized, CronScheduler cron)
+ throws ScheduleException, TaskDescriptionException {
+
+ this(SanitizedConfiguration.fromUnsanitized(unsanitized), cron);
+ }
+
+ SanitizedCronJob(SanitizedConfiguration config, CronScheduler cron) throws ScheduleException {
+ final IJobConfiguration job = config.getJobConfig();
+ if (!hasCronSchedule(job)) {
+ throw new ScheduleException(
+ String.format("Not a valid cronjob, %s has no cron schedule", JobKeys.toPath(job)));
+ }
+
+ if (!cron.isValidSchedule(job.getCronSchedule())) {
+ throw new ScheduleException("Invalid cron schedule: " + job.getCronSchedule());
+ }
+
+ this.config = config;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/state/LockManagerImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/state/LockManagerImpl.java b/src/main/java/org/apache/aurora/scheduler/state/LockManagerImpl.java
index e3b5b04..5696485 100644
--- a/src/main/java/org/apache/aurora/scheduler/state/LockManagerImpl.java
+++ b/src/main/java/org/apache/aurora/scheduler/state/LockManagerImpl.java
@@ -125,7 +125,7 @@ class LockManagerImpl implements LockManager {
private static String formatLockKey(ILockKey lockKey) {
switch (lockKey.getSetField()) {
case JOB:
- return JobKeys.canonicalString(lockKey.getJob());
+ return JobKeys.toPath(lockKey.getJob());
default:
return "Unknown lock key type: " + lockKey.getSetField();
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/state/SchedulerCoreImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/state/SchedulerCoreImpl.java b/src/main/java/org/apache/aurora/scheduler/state/SchedulerCoreImpl.java
index 09b7fbd..5369279 100644
--- a/src/main/java/org/apache/aurora/scheduler/state/SchedulerCoreImpl.java
+++ b/src/main/java/org/apache/aurora/scheduler/state/SchedulerCoreImpl.java
@@ -40,9 +40,6 @@ import org.apache.aurora.scheduler.base.Query;
import org.apache.aurora.scheduler.base.ScheduleException;
import org.apache.aurora.scheduler.base.Tasks;
import org.apache.aurora.scheduler.configuration.SanitizedConfiguration;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
import org.apache.aurora.scheduler.quota.QuotaCheckResult;
import org.apache.aurora.scheduler.quota.QuotaManager;
import org.apache.aurora.scheduler.storage.Storage;
@@ -74,7 +71,7 @@ class SchedulerCoreImpl implements SchedulerCore {
// TODO(wfarner): Consider changing this class to not be concerned with cron jobs, requiring the
// caller to deal with the fork.
- private final CronJobManager cronJobManager;
+ private final CronJobManager cronScheduler;
// State manager handles persistence of task modifications and state transitions.
private final StateManager stateManager;
@@ -86,7 +83,7 @@ class SchedulerCoreImpl implements SchedulerCore {
* Creates a new core scheduler.
*
* @param storage Backing store implementation.
- * @param cronJobManager Cron scheduler.
+ * @param cronScheduler Cron scheduler.
* @param stateManager Persistent state manager.
* @param taskIdGenerator Task ID generator.
* @param quotaManager Quota manager.
@@ -94,13 +91,13 @@ class SchedulerCoreImpl implements SchedulerCore {
@Inject
public SchedulerCoreImpl(
Storage storage,
- CronJobManager cronJobManager,
+ CronJobManager cronScheduler,
StateManager stateManager,
TaskIdGenerator taskIdGenerator,
QuotaManager quotaManager) {
this.storage = checkNotNull(storage);
- this.cronJobManager = cronJobManager;
+ this.cronScheduler = cronScheduler;
this.stateManager = checkNotNull(stateManager);
this.taskIdGenerator = checkNotNull(taskIdGenerator);
this.quotaManager = checkNotNull(quotaManager);
@@ -111,11 +108,7 @@ class SchedulerCoreImpl implements SchedulerCore {
storage,
Query.jobScoped(job.getKey()).active()).isEmpty();
- return hasActiveTasks || cronJobManager.hasJob(job.getKey());
- }
-
- private static boolean isCron(SanitizedConfiguration config) {
- return config.getJobConfig().isSetCronSchedule();
+ return hasActiveTasks || cronScheduler.hasJob(job.getKey());
}
@Override
@@ -127,19 +120,12 @@ class SchedulerCoreImpl implements SchedulerCore {
protected void execute(MutableStoreProvider storeProvider) throws ScheduleException {
final IJobConfiguration job = sanitizedConfiguration.getJobConfig();
if (hasActiveJob(job)) {
- throw new ScheduleException(
- "Job already exists: " + JobKeys.canonicalString(job.getKey()));
+ throw new ScheduleException("Job already exists: " + JobKeys.toPath(job));
}
validateTaskLimits(job.getTaskConfig(), job.getInstanceCount());
- if (isCron(sanitizedConfiguration)) {
- try {
- cronJobManager.createJob(SanitizedCronJob.from(sanitizedConfiguration));
- } catch (CronException e) {
- throw new ScheduleException(e);
- }
- } else {
+ if (!cronScheduler.receiveJob(sanitizedConfiguration)) {
LOG.info("Launching " + sanitizedConfiguration.getTaskConfigs().size() + " tasks.");
stateManager.insertPendingTasks(sanitizedConfiguration.getTaskConfigs());
}
@@ -233,7 +219,7 @@ class SchedulerCoreImpl implements SchedulerCore {
// it.
// TODO(maxim): Should be trivial to support killing multiple jobs instead.
IJobKey jobKey = Iterables.getOnlyElement(JobKeys.from(query).get());
- cronDeleted = cronJobManager.deleteJob(jobKey);
+ cronDeleted = cronScheduler.deleteJob(jobKey);
}
// Unless statuses were specifically supplied, only attempt to kill active tasks.
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/state/StateModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/state/StateModule.java b/src/main/java/org/apache/aurora/scheduler/state/StateModule.java
index 9db2a1a..7d26082 100644
--- a/src/main/java/org/apache/aurora/scheduler/state/StateModule.java
+++ b/src/main/java/org/apache/aurora/scheduler/state/StateModule.java
@@ -49,10 +49,17 @@ public class StateModule extends AbstractModule {
bind(LockManager.class).to(LockManagerImpl.class);
bind(LockManagerImpl.class).in(Singleton.class);
+ bindCronJobManager(binder());
bindMaintenanceController(binder());
}
@VisibleForTesting
+ static void bindCronJobManager(Binder binder) {
+ binder.bind(CronJobManager.class).in(Singleton.class);
+ PubsubEventModule.bindSubscriber(binder, CronJobManager.class);
+ }
+
+ @VisibleForTesting
static void bindMaintenanceController(Binder binder) {
binder.bind(MaintenanceController.class).to(MaintenanceControllerImpl.class);
binder.bind(MaintenanceControllerImpl.class).in(Singleton.class);
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
index 4e2dbeb..84151a5 100644
--- a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
+++ b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
@@ -100,14 +100,11 @@ import org.apache.aurora.scheduler.base.Tasks;
import org.apache.aurora.scheduler.configuration.ConfigurationManager;
import org.apache.aurora.scheduler.configuration.ConfigurationManager.TaskDescriptionException;
import org.apache.aurora.scheduler.configuration.SanitizedConfiguration;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.CronJobManager;
import org.apache.aurora.scheduler.cron.CronPredictor;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
import org.apache.aurora.scheduler.quota.QuotaInfo;
import org.apache.aurora.scheduler.quota.QuotaManager;
import org.apache.aurora.scheduler.quota.QuotaManager.QuotaException;
+import org.apache.aurora.scheduler.state.CronJobManager;
import org.apache.aurora.scheduler.state.LockManager;
import org.apache.aurora.scheduler.state.LockManager.LockException;
import org.apache.aurora.scheduler.state.MaintenanceController;
@@ -269,7 +266,7 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
schedulerCore.createJob(sanitized);
response.setResponseCode(OK)
.setMessage(String.format("%d new tasks pending for job %s",
- sanitized.getJobConfig().getInstanceCount(), JobKeys.canonicalString(job.getKey())));
+ sanitized.getJobConfig().getInstanceCount(), JobKeys.toPath(job)));
} catch (LockException e) {
response.setResponseCode(LOCK_ERROR).setMessage(e.getMessage());
} catch (TaskDescriptionException | ScheduleException e) {
@@ -302,11 +299,11 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
ILockKey.build(LockKey.job(jobKey.newBuilder())),
Optional.fromNullable(mutableLock).transform(ILock.FROM_BUILDER));
- cronJobManager.updateJob(SanitizedCronJob.fromUnsanitized(job));
+ cronJobManager.updateJob(SanitizedConfiguration.fromUnsanitized(job));
return response.setResponseCode(OK).setMessage("Replaced template for: " + jobKey);
} catch (LockException e) {
return response.setResponseCode(LOCK_ERROR).setMessage(e.getMessage());
- } catch (CronException | TaskDescriptionException e) {
+ } catch (TaskDescriptionException | ScheduleException e) {
return response.setResponseCode(INVALID_REQUEST).setMessage(e.getMessage());
}
}
@@ -341,16 +338,21 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
try {
sessionValidator.checkAuthenticated(session, ImmutableSet.of(jobKey.getRole()));
} catch (AuthFailedException e) {
- return response.setResponseCode(AUTH_FAILED).setMessage(e.getMessage());
+ response.setResponseCode(AUTH_FAILED).setMessage(e.getMessage());
+ return response;
}
try {
cronJobManager.startJobNow(jobKey);
- return response.setResponseCode(OK).setMessage("Cron run started.");
- } catch (CronException e) {
- return response.setResponseCode(INVALID_REQUEST)
+ response.setResponseCode(OK).setMessage("Cron run started.");
+ } catch (ScheduleException e) {
+ response.setResponseCode(INVALID_REQUEST)
.setMessage("Failed to start cron job - " + e.getMessage());
+ } catch (TaskDescriptionException e) {
+ response.setResponseCode(ERROR).setMessage("Invalid task description: " + e.getMessage());
}
+
+ return response;
}
// TODO(William Farner): Provide status information about cron jobs here.
@@ -408,14 +410,13 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
@Override
public JobSummary apply(IJobKey jobKey) {
IJobConfiguration job = jobs.get(jobKey);
- JobSummary summary = new JobSummary()
+ JobSummary smry = new JobSummary()
.setJob(job.newBuilder())
.setStats(Jobs.getJobStats(tasks.get(jobKey)).newBuilder());
return Strings.isNullOrEmpty(job.getCronSchedule())
- ? summary
- : summary.setNextCronRunMs(
- cronPredictor.predictNextRun(CrontabEntry.parse(job.getCronSchedule())).getTime());
+ ? smry
+ : smry.setNextCronRunMs(cronPredictor.predictNextRun(job.getCronSchedule()).getTime());
}
};
@@ -869,8 +870,7 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
jobsByKey(jobStore, existingJob.getKey());
switch (matches.size()) {
case 0:
- error = Optional.of(
- "No jobs found for key " + JobKeys.canonicalString(existingJob.getKey()));
+ error = Optional.of("No jobs found for key " + JobKeys.toPath(existingJob));
break;
case 1:
@@ -878,16 +878,14 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
Iterables.getOnlyElement(matches.entries());
IJobConfiguration storedJob = match.getValue();
if (!storedJob.equals(existingJob)) {
- error = Optional.of(
- "CAS compare failed for " + JobKeys.canonicalString(storedJob.getKey()));
+ error = Optional.of("CAS compare failed for " + JobKeys.toPath(storedJob));
} else {
jobStore.saveAcceptedJob(match.getKey(), rewrittenJob);
}
break;
default:
- error = Optional.of("Multiple jobs found for key "
- + JobKeys.canonicalString(existingJob.getKey()));
+ error = Optional.of("Multiple jobs found for key " + JobKeys.toPath(existingJob));
}
}
break;
[2/5] Revert "AURORA-132: Cron system based on Quartz"
Posted by ke...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobTest.java b/src/test/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobTest.java
deleted file mode 100644
index e7d1c14..0000000
--- a/src/test/java/org/apache/aurora/scheduler/cron/quartz/AuroraCronJobTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.Map;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableSet;
-import com.twitter.common.base.Supplier;
-import com.twitter.common.testing.easymock.EasyMockTest;
-import com.twitter.common.util.BackoffHelper;
-
-import org.apache.aurora.gen.AssignedTask;
-import org.apache.aurora.gen.CronCollisionPolicy;
-import org.apache.aurora.gen.ScheduleStatus;
-import org.apache.aurora.gen.ScheduledTask;
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.state.StateManager;
-import org.apache.aurora.scheduler.storage.Storage;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
-import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
-import org.apache.aurora.scheduler.storage.mem.MemStorage;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.junit.Before;
-import org.junit.Test;
-import org.quartz.JobExecutionException;
-
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class AuroraCronJobTest extends EasyMockTest {
- public static final String TASK_ID = "A";
- private Storage storage;
- private StateManager stateManager;
- private CronJobManager cronJobManager;
- private BackoffHelper backoffHelper;
-
- private AuroraCronJob auroraCronJob;
-
- private static final String MANAGER_ID = "MANAGER_ID";
-
- @Before
- public void setUp() {
- storage = MemStorage.newEmptyStorage();
- stateManager = createMock(StateManager.class);
- cronJobManager = createMock(CronJobManager.class);
- backoffHelper = createMock(BackoffHelper.class);
-
- auroraCronJob = new AuroraCronJob(
- new AuroraCronJob.Config(backoffHelper), storage, stateManager, cronJobManager);
- expect(cronJobManager.getManagerKey()).andStubReturn(MANAGER_ID);
- }
-
- @Test
- public void testExecuteNonexistentIsNoop() throws JobExecutionException {
- control.replay();
-
- auroraCronJob.doExecute(QuartzTestUtil.AURORA_JOB_KEY);
- }
-
- @Test
- public void testInvalidConfigIsNoop() throws JobExecutionException {
- control.replay();
- storage.write(new Storage.MutateWork.NoResult.Quiet() {
- @Override
- protected void execute(Storage.MutableStoreProvider storeProvider) {
- storeProvider.getJobStore().saveAcceptedJob(
- MANAGER_ID,
- IJobConfiguration.build(QuartzTestUtil.JOB.newBuilder().setCronSchedule(null)));
- }
- });
-
- auroraCronJob.doExecute(QuartzTestUtil.AURORA_JOB_KEY);
- }
-
- @Test
- public void testEmptyStorage() throws JobExecutionException {
- stateManager.insertPendingTasks(EasyMock.<Map<Integer, ITaskConfig>>anyObject());
- expectLastCall().times(3);
-
- control.replay();
- populateStorage(CronCollisionPolicy.CANCEL_NEW);
- auroraCronJob.doExecute(QuartzTestUtil.AURORA_JOB_KEY);
- storage = MemStorage.newEmptyStorage();
-
- populateStorage(CronCollisionPolicy.KILL_EXISTING);
- auroraCronJob.doExecute(QuartzTestUtil.AURORA_JOB_KEY);
- storage = MemStorage.newEmptyStorage();
-
- populateStorage(CronCollisionPolicy.RUN_OVERLAP);
- auroraCronJob.doExecute(QuartzTestUtil.AURORA_JOB_KEY);
- }
-
- @Test
- public void testCancelNew() throws JobExecutionException {
- control.replay();
-
- populateTaskStore();
- populateStorage(CronCollisionPolicy.CANCEL_NEW);
- auroraCronJob.doExecute(QuartzTestUtil.AURORA_JOB_KEY);
- }
-
- @Test
- public void testKillExisting() throws Exception {
- Capture<Supplier<Boolean>> capture = createCapture();
-
- expect(stateManager.changeState(
- TASK_ID,
- Optional.<ScheduleStatus>absent(),
- ScheduleStatus.KILLING,
- AuroraCronJob.KILL_AUDIT_MESSAGE))
- .andReturn(true);
- backoffHelper.doUntilSuccess(EasyMock.capture(capture));
- stateManager.insertPendingTasks(EasyMock.<Map<Integer, ITaskConfig>>anyObject());
-
- control.replay();
-
- populateStorage(CronCollisionPolicy.KILL_EXISTING);
- populateTaskStore();
- auroraCronJob.doExecute(QuartzTestUtil.AURORA_JOB_KEY);
- assertFalse(capture.getValue().get());
- storage.write(
- new Storage.MutateWork.NoResult.Quiet() {
- @Override
- protected void execute(Storage.MutableStoreProvider storeProvider) {
- storeProvider.getUnsafeTaskStore().deleteAllTasks();
- }
- });
- assertTrue(capture.getValue().get());
- }
-
- private void populateTaskStore() {
- storage.write(new Storage.MutateWork.NoResult.Quiet() {
- @Override
- protected void execute(Storage.MutableStoreProvider storeProvider) {
- storeProvider.getUnsafeTaskStore().saveTasks(ImmutableSet.of(
- IScheduledTask.build(new ScheduledTask()
- .setStatus(ScheduleStatus.RUNNING)
- .setAssignedTask(new AssignedTask()
- .setTaskId(TASK_ID)
- .setTask(QuartzTestUtil.JOB.getTaskConfig().newBuilder())))
- ));
- }
- });
- }
-
- private void populateStorage(final CronCollisionPolicy policy) {
- storage.write(new Storage.MutateWork.NoResult.Quiet() {
- @Override
- public void execute(Storage.MutableStoreProvider storeProvider) {
- storeProvider.getJobStore().saveAcceptedJob(
- MANAGER_ID,
- QuartzTestUtil.makeSanitizedCronJob(policy).getSanitizedConfig().getJobConfig());
- }
- });
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java b/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java
deleted file mode 100644
index 21e8278..0000000
--- a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.concurrent.CountDownLatch;
-
-import com.google.common.util.concurrent.Service;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-
-import com.google.inject.util.Modules;
-import com.twitter.common.application.ShutdownRegistry;
-import com.twitter.common.base.ExceptionalCommand;
-import com.twitter.common.testing.easymock.EasyMockTest;
-import com.twitter.common.util.Clock;
-
-import org.apache.aurora.gen.ExecutorConfig;
-import org.apache.aurora.gen.Identity;
-import org.apache.aurora.gen.JobConfiguration;
-import org.apache.aurora.gen.TaskConfig;
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
-import org.apache.aurora.scheduler.events.EventSink;
-import org.apache.aurora.scheduler.events.PubsubEvent;
-import org.apache.aurora.scheduler.state.PubsubTestUtil;
-import org.apache.aurora.scheduler.state.StateManager;
-import org.apache.aurora.scheduler.storage.Storage;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.apache.aurora.scheduler.storage.mem.MemStorage;
-import org.easymock.Capture;
-import org.easymock.IAnswer;
-import org.junit.Before;
-import org.junit.Test;
-import org.quartz.JobExecutionContext;
-import org.quartz.Scheduler;
-import org.quartz.Trigger;
-import org.quartz.TriggerListener;
-
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class CronIT extends EasyMockTest {
- public static final CrontabEntry CRONTAB_ENTRY = CrontabEntry.parse("* * * * *");
-
- private static final IJobKey JOB_KEY = JobKeys.from("roll", "b", "c");
- private static final Identity IDENTITY = new Identity()
- .setRole(JOB_KEY.getRole())
- .setUser("user");
-
- private static final IJobConfiguration CRON_JOB = IJobConfiguration.build(
- new JobConfiguration()
- .setCronSchedule(CRONTAB_ENTRY.toString())
- .setKey(JOB_KEY.newBuilder())
- .setInstanceCount(2)
- .setOwner(IDENTITY)
- .setTaskConfig(new TaskConfig()
- .setJobName(JOB_KEY.getName())
- .setEnvironment(JOB_KEY.getEnvironment())
- .setOwner(IDENTITY)
- .setExecutorConfig(new ExecutorConfig()
- .setName("cmd.exe")
- .setData("echo hello world"))
- .setNumCpus(7)
- .setRamMb(8)
- .setDiskMb(9))
- );
-
- private ShutdownRegistry shutdownRegistry;
- private EventSink eventSink;
- private Injector injector;
- private StateManager stateManager;
- private Storage storage;
- private AuroraCronJob auroraCronJob;
-
- private Capture<ExceptionalCommand<?>> shutdown;
-
- @Before
- public void setUp() throws Exception {
- shutdownRegistry = createMock(ShutdownRegistry.class);
- stateManager = createMock(StateManager.class);
- storage = MemStorage.newEmptyStorage();
- auroraCronJob = createMock(AuroraCronJob.class);
-
- injector = Guice.createInjector(
- // Override to verify that Guice is actually used for construction of the AuroraCronJob.
- // TODO(ksweeney): Use the production class here.
- Modules.override(new CronModule()).with(new AbstractModule() {
- @Override
- protected void configure() {
- bind(AuroraCronJob.class).toInstance(auroraCronJob);
- }
- }), new AbstractModule() {
- @Override
- protected void configure() {
- bind(Clock.class).toInstance(Clock.SYSTEM_CLOCK);
- bind(ShutdownRegistry.class).toInstance(shutdownRegistry);
- bind(StateManager.class).toInstance(stateManager);
- bind(Storage.class).toInstance(storage);
-
- PubsubTestUtil.installPubsub(binder());
- }
- });
- eventSink = PubsubTestUtil.startPubsub(injector);
-
- shutdown = createCapture();
- shutdownRegistry.addAction(capture(shutdown));
- }
-
- private void boot() {
- eventSink.post(new PubsubEvent.SchedulerActive());
- }
-
- @Test
- public void testCronSchedulerLifecycle() throws Exception {
- control.replay();
-
- Scheduler scheduler = injector.getInstance(Scheduler.class);
- assertTrue(!scheduler.isStarted());
-
- boot();
- Service cronLifecycle = injector.getInstance(CronLifecycle.class);
-
- assertTrue(cronLifecycle.isRunning());
- assertTrue(scheduler.isStarted());
-
- shutdown.getValue().execute();
-
- assertTrue(!cronLifecycle.isRunning());
- assertTrue(scheduler.isShutdown());
- }
-
- @Test
- public void testJobsAreScheduled() throws Exception {
- auroraCronJob.execute(isA(JobExecutionContext.class));
-
- control.replay();
- final CronJobManager cronJobManager = injector.getInstance(CronJobManager.class);
- final Scheduler scheduler = injector.getInstance(Scheduler.class);
-
- storage.write(new Storage.MutateWork.NoResult.Quiet() {
- @Override
- public void execute(Storage.MutableStoreProvider storeProvider) {
- storeProvider.getJobStore().saveAcceptedJob(
- cronJobManager.getManagerKey(),
- CRON_JOB);
- }
- });
-
- final CountDownLatch cronRan = new CountDownLatch(1);
- scheduler.getListenerManager().addTriggerListener(new CountDownWhenComplete(cronRan));
- boot();
-
- cronRan.await();
-
- shutdown.getValue().execute();
- }
-
- @Test
- public void testKillExistingDogpiles() throws Exception {
- // Test that a trigger for a job that hasn't finished running is ignored.
- final CronJobManager cronJobManager = injector.getInstance(CronJobManager.class);
-
- final CountDownLatch firstExecutionTriggered = new CountDownLatch(1);
- final CountDownLatch firstExecutionCompleted = new CountDownLatch(1);
- final CountDownLatch secondExecutionTriggered = new CountDownLatch(1);
- final CountDownLatch secondExecutionCompleted = new CountDownLatch(1);
-
- auroraCronJob.execute(isA(JobExecutionContext.class));
- expectLastCall().andAnswer(new IAnswer<Void>() {
- @Override
- public Void answer() throws Throwable {
- firstExecutionTriggered.countDown();
- firstExecutionCompleted.await();
- return null;
- }
- });
- auroraCronJob.execute(isA(JobExecutionContext.class));
- expectLastCall().andAnswer(new IAnswer<Object>() {
- @Override
- public Void answer() throws Throwable {
- secondExecutionTriggered.countDown();
- secondExecutionCompleted.await();
- return null;
- }
- });
-
- control.replay();
-
- boot();
-
- cronJobManager.createJob(SanitizedCronJob.fromUnsanitized(CRON_JOB));
- cronJobManager.startJobNow(JOB_KEY);
- firstExecutionTriggered.await();
- cronJobManager.startJobNow(JOB_KEY);
- assertEquals(1, secondExecutionTriggered.getCount());
- firstExecutionCompleted.countDown();
- secondExecutionTriggered.await();
- secondExecutionTriggered.countDown();
- }
-
- private static class CountDownWhenComplete implements TriggerListener {
- private final CountDownLatch countDownLatch;
-
- CountDownWhenComplete(CountDownLatch countDownLatch) {
- this.countDownLatch = countDownLatch;
- }
-
- @Override
- public String getName() {
- return CountDownWhenComplete.class.getName();
- }
-
- @Override
- public void triggerFired(Trigger trigger, JobExecutionContext context) {
- }
-
- @Override
- public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
- return false;
- }
-
- @Override
- public void triggerMisfired(Trigger trigger) {
- // No-op.
- }
-
- @Override
- public void triggerComplete(
- Trigger trigger,
- JobExecutionContext context,
- Trigger.CompletedExecutionInstruction triggerInstructionCode) {
-
- countDownLatch.countDown();
- // No-op.
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImplTest.java b/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImplTest.java
deleted file mode 100644
index b9116a4..0000000
--- a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronJobManagerImplTest.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.TimeZone;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.twitter.common.testing.easymock.EasyMockTest;
-
-import org.apache.aurora.gen.CronCollisionPolicy;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
-import org.apache.aurora.scheduler.storage.Storage;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.apache.aurora.scheduler.storage.mem.MemStorage;
-import org.easymock.EasyMock;
-import org.junit.Before;
-import org.junit.Test;
-import org.quartz.JobDetail;
-import org.quartz.JobKey;
-import org.quartz.Scheduler;
-import org.quartz.Trigger;
-import org.quartz.impl.matchers.GroupMatcher;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.expect;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-public class CronJobManagerImplTest extends EasyMockTest {
- private Storage storage;
- private Scheduler scheduler;
-
- private CronJobManager cronJobManager;
-
- @Before
- public void setUp() {
- storage = MemStorage.newEmptyStorage();
- scheduler = createMock(Scheduler.class);
-
- cronJobManager = new CronJobManagerImpl(storage, scheduler, TimeZone.getTimeZone("GMT"));
- }
-
- @Test
- public void testStartJobNowExistent() throws Exception {
- populateStorage();
- scheduler.triggerJob(QuartzTestUtil.QUARTZ_JOB_KEY);
-
- control.replay();
-
- cronJobManager.startJobNow(QuartzTestUtil.AURORA_JOB_KEY);
- }
-
- @Test(expected = CronException.class)
- public void testStartJobNowNonexistent() throws Exception {
- control.replay();
-
- cronJobManager.startJobNow(QuartzTestUtil.AURORA_JOB_KEY);
- }
-
- @Test
- public void testUpdateExistingJob() throws Exception {
- SanitizedCronJob sanitizedCronJob = QuartzTestUtil.makeSanitizedCronJob();
-
- expect(scheduler.deleteJob(QuartzTestUtil.QUARTZ_JOB_KEY)).andReturn(true);
- expect(scheduler.scheduleJob(anyObject(JobDetail.class), anyObject(Trigger.class)))
- .andReturn(null);
-
- populateStorage();
-
- control.replay();
-
- cronJobManager.updateJob(sanitizedCronJob);
- assertEquals(sanitizedCronJob.getSanitizedConfig().getJobConfig(), fetchFromStorage().orNull());
- }
-
- @Test
- public void testUpdateNonexistentJob() throws Exception {
- control.replay();
-
- try {
- cronJobManager.updateJob(QuartzTestUtil.makeUpdatedJob());
- fail();
- } catch (CronException e) {
- // Expected.
- }
-
- assertEquals(Optional.<IJobConfiguration>absent(), fetchFromStorage());
- }
-
- @Test
- public void testCreateNonexistentJob() throws Exception {
- SanitizedCronJob sanitizedCronJob = QuartzTestUtil.makeSanitizedCronJob();
-
- expect(scheduler.scheduleJob(anyObject(JobDetail.class), anyObject(Trigger.class)))
- .andReturn(null);
-
- control.replay();
-
- cronJobManager.createJob(sanitizedCronJob);
-
- assertEquals(
- sanitizedCronJob.getSanitizedConfig().getJobConfig(),
- fetchFromStorage().orNull());
- }
-
- @Test(expected = CronException.class)
- public void testCreateExistingJobFails() throws Exception {
- SanitizedCronJob sanitizedCronJob = QuartzTestUtil.makeSanitizedCronJob();
- populateStorage();
- control.replay();
-
- cronJobManager.createJob(sanitizedCronJob);
- }
-
- @Test
- public void testGetJobs() throws Exception {
- control.replay();
- assertEquals(Collections.emptyList(), ImmutableList.copyOf(cronJobManager.getJobs()));
-
- populateStorage();
- assertEquals(
- QuartzTestUtil.makeSanitizedCronJob().getSanitizedConfig().getJobConfig(),
- Iterables.getOnlyElement(cronJobManager.getJobs()));
- }
-
- @Test
- public void testNoRunOverlap() throws Exception {
- SanitizedCronJob runOverlapJob = SanitizedCronJob.fromUnsanitized(
- IJobConfiguration.build(QuartzTestUtil.JOB.newBuilder()
- .setCronCollisionPolicy(CronCollisionPolicy.RUN_OVERLAP)));
-
- control.replay();
-
- try {
- cronJobManager.createJob(runOverlapJob);
- fail();
- } catch (CronException e) {
- // Expected.
- }
-
- try {
- cronJobManager.updateJob(runOverlapJob);
- } catch (CronException e) {
- // Expected.
- }
-
- assertEquals(Optional.<IJobConfiguration>absent(), fetchFromStorage());
- }
-
- @Test
- public void testDeleteJob() throws Exception {
- expect(scheduler.deleteJob(QuartzTestUtil.QUARTZ_JOB_KEY)).andReturn(true);
-
- control.replay();
-
- assertFalse(cronJobManager.deleteJob(QuartzTestUtil.AURORA_JOB_KEY));
- populateStorage();
- assertTrue(cronJobManager.deleteJob(QuartzTestUtil.AURORA_JOB_KEY));
- assertEquals(Optional.<IJobConfiguration>absent(), fetchFromStorage());
- }
-
- @Test
- public void testGetScheduledJobs() throws Exception {
- JobDetail jobDetail = createMock(JobDetail.class);
- expect(scheduler.getJobKeys(EasyMock.<GroupMatcher<JobKey>>anyObject()))
- .andReturn(ImmutableSet.of(QuartzTestUtil.QUARTZ_JOB_KEY));
- expect(scheduler.getJobDetail(QuartzTestUtil.QUARTZ_JOB_KEY))
- .andReturn(jobDetail);
- expect(jobDetail.getDescription()).andReturn("* * * * *");
-
- control.replay();
-
- Map<IJobKey, CrontabEntry> scheduledJobs = cronJobManager.getScheduledJobs();
- assertEquals(CrontabEntry.parse("* * * * *"), scheduledJobs.get(QuartzTestUtil.AURORA_JOB_KEY));
- }
-
- private void populateStorage() throws Exception {
- storage.write(new Storage.MutateWork.NoResult<Exception>() {
- @Override
- protected void execute(Storage.MutableStoreProvider storeProvider) throws Exception {
- storeProvider.getJobStore().saveAcceptedJob(
- cronJobManager.getManagerKey(),
- QuartzTestUtil.makeSanitizedCronJob().getSanitizedConfig().getJobConfig());
- }
- });
- }
-
- private Optional<IJobConfiguration> fetchFromStorage() {
- return storage.consistentRead(new Storage.Work.Quiet<Optional<IJobConfiguration>>() {
- @Override
- public Optional<IJobConfiguration> apply(Storage.StoreProvider storeProvider) {
- return storeProvider.getJobStore().fetchJob(cronJobManager.getManagerKey(),
- QuartzTestUtil.AURORA_JOB_KEY);
- }
- });
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImplTest.java b/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImplTest.java
deleted file mode 100644
index 6bc97f3..0000000
--- a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronPredictorImplTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import java.util.Date;
-import java.util.List;
-import java.util.TimeZone;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Lists;
-import com.twitter.common.quantity.Amount;
-import com.twitter.common.quantity.Time;
-import com.twitter.common.util.testing.FakeClock;
-
-import org.apache.aurora.scheduler.cron.CronPredictor;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-
-import org.apache.aurora.scheduler.cron.ExpectedPrediction;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class CronPredictorImplTest {
- private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("GMT");
- public static final CrontabEntry CRONTAB_ENTRY = CrontabEntry.parse("* * * * *");
-
- private CronPredictor cronPredictor;
-
- private FakeClock clock;
-
- @Before
- public void setUp() {
- clock = new FakeClock();
- cronPredictor = new CronPredictorImpl(clock, TIME_ZONE);
- }
-
- @Test
- public void testValidSchedule() {
- clock.advance(Amount.of(1L, Time.DAYS));
- Date expectedPrediction = new Date(Amount.of(1L, Time.DAYS).as(Time.MILLISECONDS)
- + Amount.of(1L, Time.MINUTES).as(Time.MILLISECONDS));
- assertEquals(expectedPrediction, cronPredictor.predictNextRun(CrontabEntry.parse("* * * * *")));
- }
-
- @Test
- public void testCronExpressions() {
- assertEquals("0 * * ? * 1,2,3,4,5,6,7",
- Quartz.cronExpression(CRONTAB_ENTRY, TIME_ZONE).getCronExpression());
- }
-
- @Test
- public void testCronPredictorConforms() throws Exception {
- for (ExpectedPrediction expectedPrediction : ExpectedPrediction.getAll()) {
- List<Date> results = Lists.newArrayList();
- clock.setNowMillis(0);
- for (int i = 0; i < expectedPrediction.getTriggerTimes().size(); i++) {
- Date nextTriggerTime = cronPredictor.predictNextRun(expectedPrediction.parseCrontabEntry());
- results.add(nextTriggerTime);
- clock.setNowMillis(nextTriggerTime.getTime());
- }
- assertEquals(
- "Cron schedule " + expectedPrediction.getSchedule() + " made unexpected predictions.",
- Lists.transform(
- expectedPrediction.getTriggerTimes(),
- new Function<Long, Date>() {
- @Override
- public Date apply(Long time) {
- return new Date(time);
- }
- }
- ),
- results);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java b/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java
deleted file mode 100644
index b10f514..0000000
--- a/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron.quartz;
-
-import com.google.common.base.Throwables;
-
-import org.apache.aurora.gen.CronCollisionPolicy;
-import org.apache.aurora.gen.ExecutorConfig;
-import org.apache.aurora.gen.Identity;
-import org.apache.aurora.gen.JobConfiguration;
-import org.apache.aurora.gen.TaskConfig;
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.configuration.ConfigurationManager;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
-import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
-import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.quartz.JobKey;
-
-/**
- * Fixtures used across quartz tests.
- */
-final class QuartzTestUtil {
- static final IJobKey AURORA_JOB_KEY = JobKeys.from("role", "env", "job");
- static final IJobConfiguration JOB = IJobConfiguration.build(
- new JobConfiguration()
- .setCronSchedule("* * * * SUN")
- .setInstanceCount(10)
- .setOwner(new Identity("role", "user"))
- .setKey(AURORA_JOB_KEY.newBuilder())
- .setTaskConfig(new TaskConfig()
- .setOwner(new Identity("role", "user"))
- .setJobName(AURORA_JOB_KEY.getName())
- .setEnvironment(AURORA_JOB_KEY.getEnvironment())
- .setDiskMb(3)
- .setRamMb(4)
- .setNumCpus(5)
- .setExecutorConfig(new ExecutorConfig()
- .setName("cmd.exe")
- .setData("echo hello world")))
- );
- static final JobKey QUARTZ_JOB_KEY = Quartz.jobKey(AURORA_JOB_KEY);
-
- private QuartzTestUtil() {
- // Utility class.
- }
-
- static SanitizedCronJob makeSanitizedCronJob(CronCollisionPolicy collisionPolicy) {
- try {
- return SanitizedCronJob.fromUnsanitized(
- IJobConfiguration.build(JOB.newBuilder().setCronCollisionPolicy(collisionPolicy)));
- } catch (CronException | ConfigurationManager.TaskDescriptionException e) {
- throw Throwables.propagate(e);
- }
- }
-
- static SanitizedCronJob makeSanitizedCronJob() {
- return makeSanitizedCronJob(CronCollisionPolicy.KILL_EXISTING);
- }
-
- static SanitizedCronJob makeUpdatedJob() throws Exception {
- return SanitizedCronJob.fromUnsanitized(
- IJobConfiguration.build(JOB.newBuilder().setCronSchedule("* * 1 * *")));
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/state/BaseSchedulerCoreImplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/state/BaseSchedulerCoreImplTest.java b/src/test/java/org/apache/aurora/scheduler/state/BaseSchedulerCoreImplTest.java
index 2857f35..d7dbfaa 100644
--- a/src/test/java/org/apache/aurora/scheduler/state/BaseSchedulerCoreImplTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/state/BaseSchedulerCoreImplTest.java
@@ -38,6 +38,8 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Range;
import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.twitter.common.application.ShutdownRegistry;
import com.twitter.common.collections.Pair;
import com.twitter.common.testing.easymock.EasyMockTest;
import com.twitter.common.util.testing.FakeClock;
@@ -66,10 +68,7 @@ import org.apache.aurora.scheduler.base.Tasks;
import org.apache.aurora.scheduler.configuration.ConfigurationManager;
import org.apache.aurora.scheduler.configuration.ConfigurationManager.TaskDescriptionException;
import org.apache.aurora.scheduler.configuration.SanitizedConfiguration;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.CronJobManager;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
+import org.apache.aurora.scheduler.cron.CronScheduler;
import org.apache.aurora.scheduler.events.EventSink;
import org.apache.aurora.scheduler.events.PubsubEvent;
import org.apache.aurora.scheduler.quota.QuotaCheckResult;
@@ -86,7 +85,6 @@ import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
import org.apache.aurora.scheduler.storage.entities.ITaskEvent;
import org.apache.mesos.Protos.SlaveID;
import org.easymock.EasyMock;
-import org.easymock.IArgumentMatcher;
import org.easymock.IExpectationSetters;
import org.junit.Before;
import org.junit.Test;
@@ -108,10 +106,9 @@ import static org.apache.aurora.scheduler.quota.QuotaCheckResult.Result.INSUFFIC
import static org.apache.aurora.scheduler.quota.QuotaCheckResult.Result.SUFFICIENT_QUOTA;
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
-import static org.easymock.EasyMock.reportMatcher;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -131,23 +128,25 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
private static final IJobKey KEY_A = JobKeys.from(ROLE_A, ENV_A, JOB_A);
private static final int ONE_GB = 1024;
+ private static final String ROLE_B = "Test_Role_B";
+ private static final IJobKey KEY_B = JobKeys.from(ROLE_B, ENV_A, JOB_A);
+
private static final SlaveID SLAVE_ID = SlaveID.newBuilder().setValue("SlaveId").build();
private static final String SLAVE_HOST_1 = "SlaveHost1";
private static final QuotaCheckResult ENOUGH_QUOTA = new QuotaCheckResult(SUFFICIENT_QUOTA);
private static final QuotaCheckResult NOT_ENOUGH_QUOTA = new QuotaCheckResult(INSUFFICIENT_QUOTA);
- public static final CrontabEntry CRONTAB_ENTRY = CrontabEntry.parse("1 1 1 1 *");
- public static final String RAW_CRONTAB_ENTRY = CRONTAB_ENTRY.toString();
-
private Driver driver;
private StateManagerImpl stateManager;
private Storage storage;
private SchedulerCoreImpl scheduler;
- private CronJobManager cronJobManager;
+ private CronScheduler cronScheduler;
+ private CronJobManager cron;
private FakeClock clock;
private EventSink eventSink;
private RescheduleCalculator rescheduleCalculator;
+ private ShutdownRegistry shutdownRegistry;
private QuotaManager quotaManager;
// TODO(William Farner): Set up explicit expectations for calls to generate task IDs.
@@ -165,15 +164,18 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
clock = new FakeClock();
eventSink = createMock(EventSink.class);
rescheduleCalculator = createMock(RescheduleCalculator.class);
- cronJobManager = createMock(CronJobManager.class);
+ cronScheduler = createMock(CronScheduler.class);
+ shutdownRegistry = createMock(ShutdownRegistry.class);
quotaManager = createMock(QuotaManager.class);
eventSink.post(EasyMock.<PubsubEvent>anyObject());
expectLastCall().anyTimes();
+ expect(cronScheduler.schedule(anyObject(String.class), anyObject(Runnable.class)))
+ .andStubReturn("key");
+ expect(cronScheduler.isValidSchedule(anyObject(String.class))).andStubReturn(true);
expect(quotaManager.checkQuota(anyObject(ITaskConfig.class), anyInt()))
.andStubReturn(ENOUGH_QUOTA);
- expect(cronJobManager.hasJob(anyObject(IJobKey.class))).andStubReturn(false);
}
/**
@@ -206,9 +208,15 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
taskIdGenerator,
eventSink,
rescheduleCalculator);
+ cron = new CronJobManager(
+ stateManager,
+ storage,
+ cronScheduler,
+ shutdownRegistry,
+ MoreExecutors.sameThreadExecutor());
scheduler = new SchedulerCoreImpl(
storage,
- cronJobManager,
+ cron,
stateManager,
taskIdGenerator,
quotaManager);
@@ -264,7 +272,7 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
buildScheduler();
TaskConfig newTask = nonProductionTask();
- newTask.addToConstraints(dedicatedConstraint(ImmutableSet.of(JobKeys.canonicalString(KEY_A))));
+ newTask.addToConstraints(dedicatedConstraint(ImmutableSet.of(JobKeys.toPath(KEY_A))));
scheduler.createJob(makeJob(KEY_A, newTask));
assertEquals(PENDING, getOnlyTask(Query.jobScoped(KEY_A)).getStatus());
}
@@ -437,6 +445,147 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
scheduler.createJob(makeJob(KEY_A, 1));
}
+ @Test(expected = ScheduleException.class)
+ public void testCreateDuplicateCronJob() throws Exception {
+ SanitizedConfiguration sanitizedConfiguration = makeCronJob(KEY_A, 1, "1 1 1 1 1");
+
+ control.replay();
+ buildScheduler();
+
+ // Cron jobs are scheduled on a delay, so this job's tasks will not be scheduled immediately,
+ // but duplicate jobs should still be rejected.
+ scheduler.createJob(sanitizedConfiguration);
+ assertTaskCount(0);
+
+ scheduler.createJob(makeJob(KEY_A, 1));
+ }
+
+ @Test
+ public void testStartCronJob() throws Exception {
+ // Create a cron job, ask the scheduler to start it, and ensure that the tasks exist
+ // in the PENDING state.
+
+ SanitizedConfiguration sanitizedConfiguration = makeCronJob(KEY_A, 1, "1 1 1 1 1");
+ IJobKey jobKey = sanitizedConfiguration.getJobConfig().getKey();
+
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(sanitizedConfiguration);
+ assertTaskCount(0);
+
+ cron.startJobNow(jobKey);
+ assertEquals(PENDING, getOnlyTask(Query.jobScoped(jobKey)).getStatus());
+ }
+
+ @Test(expected = ScheduleException.class)
+ public void testStartNonexistentCronJob() throws Exception {
+ // Try to start a cron job that doesn't exist.
+ control.replay();
+ buildScheduler();
+
+ cron.startJobNow(KEY_A);
+ }
+
+ @Test
+ public void testStartNonCronJob() throws Exception {
+ // Create a NON cron job and try to start it as though it were a cron job, and ensure that
+ // no cron tasks are created.
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(makeJob(KEY_A, 1));
+ String taskId = Tasks.id(getOnlyTask(Query.jobScoped(KEY_A)));
+
+ try {
+ cron.startJobNow(KEY_A);
+ fail("Start should have failed.");
+ } catch (ScheduleException e) {
+ // Expected.
+ }
+
+ assertEquals(PENDING, getTask(taskId).getStatus());
+ assertFalse(cron.hasJob(KEY_A));
+ }
+
+ @Test(expected = ScheduleException.class)
+ public void testStartNonOwnedCronJob() throws Exception {
+ // Try to start a cron job that is not owned by us.
+ // Should throw an exception.
+
+ SanitizedConfiguration sanitizedConfiguration = makeCronJob(KEY_A, 1, "1 1 1 1 1");
+ IJobConfiguration job = sanitizedConfiguration.getJobConfig();
+ expect(cronScheduler.isValidSchedule(job.getCronSchedule())).andReturn(true);
+ expect(cronScheduler.schedule(eq(job.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andReturn("key");
+
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(sanitizedConfiguration);
+ assertTaskCount(0);
+
+ cron.startJobNow(KEY_B);
+ }
+
+ @Test
+ public void testStartRunningCronJob() throws Exception {
+ // Start a cron job that is already started by an earlier
+ // call and is PENDING. Make sure it follows the cron collision policy.
+ SanitizedConfiguration sanitizedConfiguration =
+ makeCronJob(KEY_A, 1, "1 1 1 1 1", CronCollisionPolicy.KILL_EXISTING);
+ expect(cronScheduler.schedule(eq(sanitizedConfiguration.getJobConfig().getCronSchedule()),
+ EasyMock.<Runnable>anyObject()))
+ .andReturn("key");
+
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(sanitizedConfiguration);
+ assertTaskCount(0);
+ assertTrue(cron.hasJob(KEY_A));
+
+ cron.startJobNow(KEY_A);
+ assertTaskCount(1);
+
+ String taskId = Tasks.id(getOnlyTask(Query.jobScoped(KEY_A)));
+
+ // Now start the same cron job immediately.
+ cron.startJobNow(KEY_A);
+ assertTaskCount(1);
+ assertEquals(PENDING, getOnlyTask(Query.jobScoped(KEY_A)).getStatus());
+
+ // Make sure the pending job is the new one.
+ String newTaskId = Tasks.id(getOnlyTask(Query.jobScoped(KEY_A)));
+ assertFalse(taskId.equals(newTaskId));
+ }
+
+ @Test
+ public void testKillCreateCronJob() throws Exception {
+ SanitizedConfiguration sanitizedConfiguration = makeCronJob(KEY_A, 1, "1 1 1 1 1");
+ IJobConfiguration job = sanitizedConfiguration.getJobConfig();
+ expect(cronScheduler.schedule(eq(job.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andReturn("key");
+ cronScheduler.deschedule("key");
+
+ SanitizedConfiguration updated = makeCronJob(KEY_A, 1, "1 2 3 4 5");
+ IJobConfiguration updatedJob = updated.getJobConfig();
+ expect(cronScheduler.schedule(eq(updatedJob.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andReturn("key2");
+
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(sanitizedConfiguration);
+ assertTrue(cron.hasJob(KEY_A));
+
+ scheduler.killTasks(Query.jobScoped(KEY_A), OWNER_A.getUser());
+ scheduler.createJob(updated);
+
+ IJobConfiguration stored = Iterables.getOnlyElement(cron.getJobs());
+ assertEquals(updatedJob.getCronSchedule(), stored.getCronSchedule());
+ }
+
@Test
public void testKillTask() throws Exception {
driver.killTask(EasyMock.<String>anyObject());
@@ -482,21 +631,17 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
@Test
public void testServiceTasksRescheduled() throws Exception {
int numServiceTasks = 5;
- IJobKey adhocKey = KEY_A;
- IJobKey serviceKey = IJobKey.build(
- adhocKey.newBuilder().setName(adhocKey.getName() + "service"));
expectTaskNotThrottled().times(numServiceTasks);
- expectNoCronJob(adhocKey);
- expectNoCronJob(serviceKey);
control.replay();
buildScheduler();
// Schedule 5 service and 5 non-service tasks.
- scheduler.createJob(makeJob(adhocKey, numServiceTasks));
+ scheduler.createJob(makeJob(KEY_A, numServiceTasks));
TaskConfig task = productionTask().setIsService(true);
- scheduler.createJob(makeJob(serviceKey, task, 5));
+ scheduler.createJob(
+ makeJob(IJobKey.build(KEY_A.newBuilder().setName(KEY_A.getName() + "service")), task, 5));
assertEquals(10, getTasksByStatus(PENDING).size());
changeStatus(Query.roleScoped(ROLE_A), ASSIGNED, STARTING);
@@ -523,7 +668,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
int totalFailures = 10;
expectTaskNotThrottled().times(totalFailures);
- expectNoCronJob(KEY_A);
control.replay();
buildScheduler();
@@ -582,7 +726,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
@Test
public void testNoTransitionFromTerminalState() throws Exception {
expectKillTask(1);
- expectNoCronJob(KEY_A);
control.replay();
buildScheduler();
@@ -603,7 +746,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
public void testFailedTaskIncrementsFailureCount() throws Exception {
int maxFailures = 5;
expectTaskNotThrottled().times(maxFailures - 1);
- expect(cronJobManager.hasJob(KEY_A)).andReturn(false);
control.replay();
buildScheduler();
@@ -636,9 +778,78 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
}
@Test
- public void testKillPendingTask() throws Exception {
- expectNoCronJob(KEY_A);
+ public void testCronJobLifeCycle() throws Exception {
+ SanitizedConfiguration sanitizedConfiguration = makeCronJob(KEY_A, 10, "1 1 1 1 1");
+ IJobConfiguration job = sanitizedConfiguration.getJobConfig();
+ expect(cronScheduler.schedule(eq(job.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andReturn("key");
+
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(sanitizedConfiguration);
+ assertTaskCount(0);
+ assertTrue(cron.hasJob(KEY_A));
+
+ // Simulate a triggering of the cron job.
+ cron.startJobNow(KEY_A);
+ assertTaskCount(10);
+ assertEquals(10,
+ getTasks(Query.jobScoped(KEY_A).byStatus(PENDING)).size());
+
+ assertTaskCount(10);
+
+ changeStatus(Query.roleScoped(ROLE_A), ASSIGNED, STARTING);
+ assertTaskCount(10);
+ changeStatus(Query.roleScoped(ROLE_A), RUNNING);
+ assertTaskCount(10);
+ changeStatus(Query.roleScoped(ROLE_A), FINISHED);
+ }
+
+ @Test
+ public void testCronNoSuicide() throws Exception {
+ SanitizedConfiguration sanitizedConfiguration =
+ makeCronJob(KEY_A, 10, "1 1 1 1 1", CronCollisionPolicy.KILL_EXISTING);
+ expect(cronScheduler.schedule(eq(sanitizedConfiguration.getJobConfig().getCronSchedule()),
+ EasyMock.<Runnable>anyObject()))
+ .andReturn("key");
+
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(sanitizedConfiguration);
+ assertTaskCount(0);
+
+ try {
+ scheduler.createJob(sanitizedConfiguration);
+ fail();
+ } catch (ScheduleException e) {
+ // Expected.
+ }
+ assertTrue(cron.hasJob(KEY_A));
+
+ // Simulate a triggering of the cron job.
+ cron.startJobNow(KEY_A);
+ assertTaskCount(10);
+ Set<String> taskIds = Tasks.ids(getTasksOwnedBy(OWNER_A));
+
+ // Simulate a triggering of the cron job.
+ cron.startJobNow(KEY_A);
+ assertTaskCount(10);
+ assertTrue(Sets.intersection(taskIds, Tasks.ids(getTasksOwnedBy(OWNER_A))).isEmpty());
+
+ try {
+ scheduler.createJob(sanitizedConfiguration);
+ fail();
+ } catch (ScheduleException e) {
+ // Expected.
+ }
+ assertTrue(cron.hasJob(KEY_A));
+ }
+
+ @Test
+ public void testKillPendingTask() throws Exception {
control.replay();
buildScheduler();
@@ -673,12 +884,16 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
@Test
public void testKillCronTask() throws Exception {
- expect(cronJobManager.hasJob(KEY_A)).andReturn(false);
- cronJobManager.createJob(anyObject(SanitizedCronJob.class));
- expect(cronJobManager.deleteJob(KEY_A)).andReturn(true);
+ SanitizedConfiguration sanitizedConfiguration =
+ makeCronJob(KEY_A, 1, "1 1 1 1 1", CronCollisionPolicy.KILL_EXISTING);
+ expect(cronScheduler.schedule(eq(sanitizedConfiguration.getJobConfig().getCronSchedule()),
+ EasyMock.<Runnable>anyObject()))
+ .andReturn("key");
+ cronScheduler.deschedule("key");
+
control.replay();
buildScheduler();
- scheduler.createJob(makeCronJob(KEY_A, 1, RAW_CRONTAB_ENTRY));
+ scheduler.createJob(makeCronJob(KEY_A, 1, "1 1 1 1 1"));
// This will fail if the cron task could not be found.
scheduler.killTasks(Query.jobScoped(KEY_A), OWNER_A.getUser());
@@ -688,7 +903,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
public void testLostTaskRescheduled() throws Exception {
expectKillTask(2);
expectTaskNotThrottled().times(2);
- expect(cronJobManager.hasJob(KEY_A)).andReturn(false);
control.replay();
buildScheduler();
@@ -718,10 +932,32 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
}
@Test
- public void testKillJob() throws Exception {
- expectNoCronJob(KEY_A);
- expect(cronJobManager.deleteJob(KEY_A)).andReturn(false);
+ public void testKillNotStrictlyJobScoped() throws Exception {
+ // Makes sure that queries that are not strictly job scoped will not remove the job entirely.
+ SanitizedConfiguration config = makeCronJob(KEY_A, 10, "1 1 1 1 1");
+ IJobConfiguration job = config.getJobConfig();
+ expect(cronScheduler.schedule(eq(job.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andReturn("key");
+ cronScheduler.deschedule("key");
+
+ control.replay();
+ buildScheduler();
+
+ scheduler.createJob(config);
+ assertTrue(cron.hasJob(KEY_A));
+ cron.startJobNow(KEY_A);
+ assertTaskCount(10);
+
+ scheduler.killTasks(Query.instanceScoped(KEY_A, 0), USER_A);
+ assertTaskCount(9);
+ assertTrue(cron.hasJob(KEY_A));
+ scheduler.killTasks(Query.jobScoped(KEY_A), USER_A);
+ assertFalse(cron.hasJob(KEY_A));
+ }
+
+ @Test
+ public void testKillJob() throws Exception {
control.replay();
buildScheduler();
@@ -772,7 +1008,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
@Test(expected = ScheduleException.class)
public void testRestartNonexistentShard() throws Exception {
expectTaskNotThrottled();
- expectNoCronJob(KEY_A);
control.replay();
buildScheduler();
@@ -784,8 +1019,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
@Test
public void testRestartPendingShard() throws Exception {
- expect(cronJobManager.hasJob(KEY_A)).andReturn(false);
-
control.replay();
buildScheduler();
@@ -818,7 +1051,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
public void testPortResourceResetAfterReschedule() throws Exception {
expectKillTask(1);
expectTaskNotThrottled();
- expect(cronJobManager.hasJob(KEY_A)).andReturn(false);
control.replay();
buildScheduler();
@@ -881,7 +1113,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
}
};
- expectNoCronJob(KEY_A);
control.replay();
buildScheduler();
@@ -936,8 +1167,9 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
scheduler.addInstances(
job.getKey(),
- ContiguousSet.create(Range.closed(0, SchedulerCoreImpl.MAX_TASKS_PER_JOB.get()),
- DiscreteDomain.integers()),
+ ImmutableSet.copyOf(
+ ContiguousSet.create(Range.closed(0, SchedulerCoreImpl.MAX_TASKS_PER_JOB.get()),
+ DiscreteDomain.integers())),
job.getTaskConfig());
}
@@ -986,7 +1218,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
.setOwner(OWNER_A);
ImmutableSet<Integer> instances = ImmutableSet.of(0);
- expectNoCronJob(KEY_A);
control.replay();
buildScheduler();
@@ -997,14 +1228,6 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
scheduler.addInstances(KEY_A, instances, ITaskConfig.build(newTask));
}
- private void expectNoCronJob(int times) throws CronException {
- expect(cronJobManager.hasJob(isA(IJobKey.class))).andReturn(false).times(times);
- }
-
- private void expectNoCronJob(IJobKey jobKey) throws CronException {
- expect(cronJobManager.hasJob(jobKey)).andReturn(false);
- }
-
private static String getLocalHost() {
try {
return InetAddress.getLocalHost().getHostName();
@@ -1171,23 +1394,4 @@ public abstract class BaseSchedulerCoreImplTest extends EasyMockTest {
public void changeStatus(String taskId, ScheduleStatus status, Optional<String> message) {
changeStatus(Query.taskScoped(taskId), status, message);
}
-
- private SanitizedConfiguration hasJobKey(final IJobKey key) {
- reportMatcher(new IArgumentMatcher() {
- @Override
- public boolean matches(Object item) {
- if (!(item instanceof SanitizedConfiguration)) {
- return false;
- }
- SanitizedConfiguration configuration = (SanitizedConfiguration) item;
- return key.equals(configuration.getJobConfig().getKey());
- }
-
- @Override
- public void appendTo(StringBuffer buffer) {
- buffer.append(key.toString());
- }
- });
- return null;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/state/CronJobManagerTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/state/CronJobManagerTest.java b/src/test/java/org/apache/aurora/scheduler/state/CronJobManagerTest.java
new file mode 100644
index 0000000..fa9cb75
--- /dev/null
+++ b/src/test/java/org/apache/aurora/scheduler/state/CronJobManagerTest.java
@@ -0,0 +1,490 @@
+/**
+ * Copyright 2013 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.state;
+
+import java.util.concurrent.Executor;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.twitter.common.application.ShutdownRegistry;
+import com.twitter.common.base.ExceptionalCommand;
+import com.twitter.common.testing.easymock.EasyMockTest;
+
+import org.apache.aurora.gen.AssignedTask;
+import org.apache.aurora.gen.CronCollisionPolicy;
+import org.apache.aurora.gen.ExecutorConfig;
+import org.apache.aurora.gen.Identity;
+import org.apache.aurora.gen.JobConfiguration;
+import org.apache.aurora.gen.ScheduleStatus;
+import org.apache.aurora.gen.ScheduledTask;
+import org.apache.aurora.gen.TaskConfig;
+import org.apache.aurora.scheduler.base.JobKeys;
+import org.apache.aurora.scheduler.base.Query;
+import org.apache.aurora.scheduler.base.ScheduleException;
+import org.apache.aurora.scheduler.configuration.SanitizedConfiguration;
+import org.apache.aurora.scheduler.cron.CronException;
+import org.apache.aurora.scheduler.cron.CronScheduler;
+import org.apache.aurora.scheduler.events.EventSink;
+import org.apache.aurora.scheduler.events.PubsubEvent.SchedulerActive;
+import org.apache.aurora.scheduler.storage.Storage;
+import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
+import org.apache.aurora.scheduler.storage.entities.IJobKey;
+import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
+import org.apache.aurora.scheduler.storage.testing.StorageTestUtil;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IExpectationSetters;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.aurora.gen.apiConstants.DEFAULT_ENVIRONMENT;
+import static org.apache.aurora.scheduler.state.CronJobManager.MANAGER_KEY;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class CronJobManagerTest extends EasyMockTest {
+
+ private static final String OWNER = "owner";
+ private static final String ENVIRONMENT = "staging11";
+ private static final String JOB_NAME = "jobName";
+ private static final String DEFAULT_JOB_KEY = "key";
+ private static final String TASK_ID = "id";
+ private static final IScheduledTask TASK = IScheduledTask.build(
+ new ScheduledTask().setAssignedTask(new AssignedTask().setTaskId(TASK_ID)));
+
+ private StateManager stateManager;
+ private Executor delayExecutor;
+ private Capture<Runnable> delayLaunchCapture;
+ private StorageTestUtil storageUtil;
+
+ private CronScheduler cronScheduler;
+ private ShutdownRegistry shutdownRegistry;
+ private CronJobManager cron;
+ private IJobConfiguration job;
+ private SanitizedConfiguration sanitizedConfiguration;
+
+ @Before
+ public void setUp() throws Exception {
+ stateManager = createMock(StateManager.class);
+ delayExecutor = createMock(Executor.class);
+ delayLaunchCapture = createCapture();
+ storageUtil = new StorageTestUtil(this);
+ storageUtil.expectOperations();
+ cronScheduler = createMock(CronScheduler.class);
+ shutdownRegistry = createMock(ShutdownRegistry.class);
+
+ cron = new CronJobManager(
+ stateManager,
+ storageUtil.storage,
+ cronScheduler,
+ shutdownRegistry,
+ delayExecutor);
+ job = makeJob();
+ sanitizedConfiguration = SanitizedConfiguration.fromUnsanitized(job);
+ }
+
+ private void expectJobValidated(IJobConfiguration savedJob) {
+ expect(cronScheduler.isValidSchedule(savedJob.getCronSchedule())).andReturn(true);
+ }
+
+ private void expectJobValidated() {
+ expectJobValidated(sanitizedConfiguration.getJobConfig());
+ }
+
+ private Capture<Runnable> expectJobAccepted(IJobConfiguration savedJob) throws Exception {
+ expectJobValidated(savedJob);
+ storageUtil.jobStore.saveAcceptedJob(MANAGER_KEY, savedJob);
+ Capture<Runnable> jobTriggerCapture = createCapture();
+ expect(cronScheduler.schedule(eq(savedJob.getCronSchedule()), capture(jobTriggerCapture)))
+ .andReturn(DEFAULT_JOB_KEY);
+ return jobTriggerCapture;
+ }
+
+ private void expectJobAccepted() throws Exception {
+ expectJobAccepted(sanitizedConfiguration.getJobConfig());
+ }
+
+ private void expectJobFetch() {
+ expectJobValidated();
+ expect(storageUtil.jobStore.fetchJob(MANAGER_KEY, job.getKey()))
+ .andReturn(Optional.of(sanitizedConfiguration.getJobConfig()));
+ }
+
+ private IExpectationSetters<?> expectActiveTaskFetch(IScheduledTask... activeTasks) {
+ return storageUtil.expectTaskFetch(Query.jobScoped(job.getKey()).active(), activeTasks);
+ }
+
+ @Test
+ public void testPubsubWiring() throws Exception {
+ expect(cronScheduler.startAsync()).andReturn(cronScheduler);
+ cronScheduler.awaitRunning();
+ shutdownRegistry.addAction(EasyMock.<ExceptionalCommand<?>>anyObject());
+ expect(storageUtil.jobStore.fetchJobs(MANAGER_KEY))
+ .andReturn(ImmutableList.<IJobConfiguration>of());
+
+ control.replay();
+
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(StateManager.class).toInstance(stateManager);
+ bind(Storage.class).toInstance(storageUtil.storage);
+ bind(CronScheduler.class).toInstance(cronScheduler);
+ bind(ShutdownRegistry.class).toInstance(shutdownRegistry);
+ PubsubTestUtil.installPubsub(binder());
+ StateModule.bindCronJobManager(binder());
+ }
+ });
+ cron = injector.getInstance(CronJobManager.class);
+ EventSink eventSink = PubsubTestUtil.startPubsub(injector);
+ eventSink.post(new SchedulerActive());
+ }
+
+ @Test
+ public void testStart() throws Exception {
+ expectJobAccepted();
+ expectJobFetch();
+ expectActiveTaskFetch();
+
+ // Job is executed immediately since there are no existing tasks to kill.
+ stateManager.insertPendingTasks(sanitizedConfiguration.getTaskConfigs());
+ expect(cronScheduler.getSchedule(DEFAULT_JOB_KEY))
+ .andReturn(Optional.of(job.getCronSchedule()))
+ .times(2);
+
+ control.replay();
+
+ assertEquals(ImmutableMap.<IJobKey, String>of(), cron.getScheduledJobs());
+ cron.receiveJob(sanitizedConfiguration);
+ assertEquals(ImmutableMap.of(job.getKey(), job.getCronSchedule()), cron.getScheduledJobs());
+ cron.startJobNow(job.getKey());
+ assertEquals(ImmutableMap.of(job.getKey(), job.getCronSchedule()), cron.getScheduledJobs());
+ }
+
+ @Test
+ public void testDeleteInconsistent() throws Exception {
+ // Tests a case where a job exists in the storage, but is not registered with the cron system.
+
+ expect(storageUtil.jobStore.fetchJob(MANAGER_KEY, job.getKey()))
+ .andReturn(Optional.of(sanitizedConfiguration.getJobConfig()));
+
+ control.replay();
+
+ assertTrue(cron.deleteJob(job.getKey()));
+ }
+
+ private IExpectationSetters<?> expectTaskKilled(String id) {
+ expect(stateManager.changeState(
+ id,
+ Optional.<ScheduleStatus>absent(),
+ ScheduleStatus.KILLING,
+ CronJobManager.KILL_AUDIT_MESSAGE))
+ .andReturn(true);
+ return expectLastCall();
+ }
+
+ @Test
+ public void testDelayedStart() throws Exception {
+ expectJobAccepted();
+ expectJobFetch();
+
+ // Query to test if live tasks exist for the job.
+ expectActiveTaskFetch(TASK);
+
+ // Live tasks exist, so the cron manager must delay the cron launch.
+ delayExecutor.execute(capture(delayLaunchCapture));
+
+ // The cron manager will then try to initiate the kill.
+ expectTaskKilled(TASK_ID);
+
+ // Immediate query and delayed query.
+ expectActiveTaskFetch(TASK).times(2);
+
+ // Simulate the live task disappearing.
+ expectActiveTaskFetch();
+
+ stateManager.insertPendingTasks(sanitizedConfiguration.getTaskConfigs());
+
+ control.replay();
+
+ cron.receiveJob(sanitizedConfiguration);
+ cron.startJobNow(job.getKey());
+ assertEquals(ImmutableSet.of(job.getKey()), cron.getPendingRuns());
+ delayLaunchCapture.getValue().run();
+ assertEquals(ImmutableSet.<IJobKey>of(), cron.getPendingRuns());
+ }
+
+ @Test
+ public void testDelayedStartResets() throws Exception {
+ expectJobAccepted();
+ expectJobFetch();
+
+ // Query to test if live tasks exist for the job.
+ expectActiveTaskFetch(TASK);
+
+ // Live tasks exist, so the cron manager must delay the cron launch.
+ delayExecutor.execute(capture(delayLaunchCapture));
+
+ // The cron manager will then try to initiate the kill.
+ expectTaskKilled(TASK_ID);
+
+ // Immediate query and delayed query.
+ expectActiveTaskFetch(TASK).times(2);
+
+ // Simulate the live task disappearing.
+ expectActiveTaskFetch();
+
+ // Round two.
+ expectJobFetch();
+ expectActiveTaskFetch(TASK);
+ delayExecutor.execute(capture(delayLaunchCapture));
+ expectTaskKilled(TASK_ID);
+ expectActiveTaskFetch(TASK).times(2);
+ expectActiveTaskFetch();
+
+ stateManager.insertPendingTasks(sanitizedConfiguration.getTaskConfigs());
+ expectLastCall().times(2);
+
+ control.replay();
+
+ cron.receiveJob(sanitizedConfiguration);
+ cron.startJobNow(job.getKey());
+ delayLaunchCapture.getValue().run();
+
+ // Start the job again. Since the previous delayed start completed, this should repeat the
+ // entire process.
+ cron.startJobNow(job.getKey());
+ delayLaunchCapture.getValue().run();
+ }
+
+ @Test
+ public void testDelayedStartMultiple() throws Exception {
+ expectJobAccepted();
+ expectJobFetch();
+
+ // Query to test if live tasks exist for the job.
+ expectActiveTaskFetch(TASK).times(3);
+
+ // Live tasks exist, so the cron manager must delay the cron launch.
+ delayExecutor.execute(capture(delayLaunchCapture));
+
+ // The cron manager will then try to initiate the kill.
+ expectJobFetch();
+ expectJobFetch();
+ expectTaskKilled(TASK_ID).times(3);
+
+ // Immediate queries and delayed query.
+ expectActiveTaskFetch(TASK).times(4);
+
+ // Simulate the live task disappearing.
+ expectActiveTaskFetch();
+
+ stateManager.insertPendingTasks(sanitizedConfiguration.getTaskConfigs());
+
+ control.replay();
+
+ cron.receiveJob(sanitizedConfiguration);
+
+ // Attempt to trick the cron manager into launching multiple times, or launching multiple
+ // pollers.
+ cron.startJobNow(job.getKey());
+ cron.startJobNow(job.getKey());
+ cron.startJobNow(job.getKey());
+ delayLaunchCapture.getValue().run();
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ SanitizedConfiguration updated = new SanitizedConfiguration(
+ IJobConfiguration.build(job.newBuilder().setCronSchedule("1 2 3 4 5")));
+
+ expectJobAccepted();
+ cronScheduler.deschedule(DEFAULT_JOB_KEY);
+ expectJobAccepted(updated.getJobConfig());
+
+ control.replay();
+
+ cron.receiveJob(sanitizedConfiguration);
+ cron.updateJob(updated);
+ }
+
+ @Test
+ public void testConsistentState() throws Exception {
+ IJobConfiguration updated =
+ IJobConfiguration.build(makeJob().newBuilder().setCronSchedule("1 2 3 4 5"));
+
+ expectJobAccepted();
+ cronScheduler.deschedule(DEFAULT_JOB_KEY);
+ expectJobAccepted(updated);
+
+ control.replay();
+
+ cron.receiveJob(sanitizedConfiguration);
+
+ IJobConfiguration failedUpdate =
+ IJobConfiguration.build(updated.newBuilder().setCronSchedule(null));
+ try {
+ cron.updateJob(new SanitizedConfiguration(failedUpdate));
+ fail();
+ } catch (ScheduleException e) {
+ // Expected.
+ }
+
+ cron.updateJob(new SanitizedConfiguration(updated));
+ }
+
+ @Test
+ public void testInvalidStoredJob() throws Exception {
+ // Invalid jobs are left alone, but doesn't halt operation.
+
+ expect(cronScheduler.startAsync()).andReturn(cronScheduler);
+ cronScheduler.awaitRunning();
+ shutdownRegistry.addAction(EasyMock.<ExceptionalCommand<?>>anyObject());
+
+ IJobConfiguration jobA =
+ IJobConfiguration.build(makeJob().newBuilder().setCronSchedule("1 2 3 4 5 6 7"));
+ IJobConfiguration jobB =
+ IJobConfiguration.build(makeJob().newBuilder().setCronSchedule(null));
+
+ expect(storageUtil.jobStore.fetchJobs(MANAGER_KEY)).andReturn(ImmutableList.of(jobA, jobB));
+ expect(cronScheduler.isValidSchedule(jobA.getCronSchedule())).andReturn(false);
+
+ control.replay();
+
+ cron.schedulerActive(new SchedulerActive());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testJobStoredTwice() throws Exception {
+ // Simulate an inconsistent storage that contains two cron jobs under the same key.
+
+ expect(cronScheduler.startAsync()).andReturn(cronScheduler);
+ cronScheduler.awaitRunning();
+ shutdownRegistry.addAction(EasyMock.<ExceptionalCommand<?>>anyObject());
+
+ IJobConfiguration jobA =
+ IJobConfiguration.build(makeJob().newBuilder().setCronSchedule("1 2 3 4 5"));
+ IJobConfiguration jobB =
+ IJobConfiguration.build(makeJob().newBuilder().setCronSchedule("* * * * *"));
+ expect(storageUtil.jobStore.fetchJobs(MANAGER_KEY))
+ .andReturn(ImmutableList.of(jobA, jobB));
+ expectJobValidated(jobA);
+ expect(cronScheduler.schedule(eq(jobA.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andReturn("keyA");
+ expectJobValidated(jobB);
+
+ control.replay();
+
+ cron.schedulerActive(new SchedulerActive());
+ }
+
+ @Test(expected = ScheduleException.class)
+ public void testInvalidCronSchedule() throws Exception {
+ expect(cronScheduler.isValidSchedule(job.getCronSchedule())).andReturn(false);
+
+ control.replay();
+
+ cron.receiveJob(sanitizedConfiguration);
+ }
+
+ @Test
+ public void testCancelNewCollision() throws Exception {
+ IJobConfiguration killExisting = IJobConfiguration.build(
+ job.newBuilder().setCronCollisionPolicy(CronCollisionPolicy.CANCEL_NEW));
+ Capture<Runnable> jobTriggerCapture = expectJobAccepted(killExisting);
+ expectActiveTaskFetch(TASK);
+
+ control.replay();
+
+ cron.receiveJob(new SanitizedConfiguration(killExisting));
+ jobTriggerCapture.getValue().run();
+ }
+
+ @Test(expected = ScheduleException.class)
+ public void testScheduleFails() throws Exception {
+ expectJobValidated(job);
+ storageUtil.jobStore.saveAcceptedJob(MANAGER_KEY, sanitizedConfiguration.getJobConfig());
+ expect(cronScheduler.schedule(eq(job.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andThrow(new CronException("injected"));
+
+ control.replay();
+
+ cron.receiveJob(sanitizedConfiguration);
+ }
+
+ @Test(expected = ScheduleException.class)
+ public void testRunOverlapRejected() throws Exception {
+ IJobConfiguration killExisting = IJobConfiguration.build(
+ job.newBuilder().setCronCollisionPolicy(CronCollisionPolicy.RUN_OVERLAP));
+
+ control.replay();
+
+ cron.receiveJob(new SanitizedConfiguration(killExisting));
+ }
+
+ @Test
+ public void testRunOverlapLoadedSuccessfully() throws Exception {
+ // Existing RUN_OVERLAP jobs should still load and map.
+
+ expect(cronScheduler.startAsync()).andReturn(cronScheduler);
+ cronScheduler.awaitRunning();
+ shutdownRegistry.addAction(EasyMock.<ExceptionalCommand<?>>anyObject());
+
+ IJobConfiguration jobA =
+ IJobConfiguration.build(makeJob().newBuilder()
+ .setCronCollisionPolicy(CronCollisionPolicy.RUN_OVERLAP));
+
+ expect(storageUtil.jobStore.fetchJobs(MANAGER_KEY)).andReturn(ImmutableList.of(jobA));
+ expect(cronScheduler.isValidSchedule(jobA.getCronSchedule())).andReturn(true);
+ expect(cronScheduler.schedule(eq(jobA.getCronSchedule()), EasyMock.<Runnable>anyObject()))
+ .andReturn("keyA");
+
+ control.replay();
+
+ cron.schedulerActive(new SchedulerActive());
+ }
+
+ private IJobConfiguration makeJob() {
+ return IJobConfiguration.build(new JobConfiguration()
+ .setOwner(new Identity(OWNER, OWNER))
+ .setKey(JobKeys.from(OWNER, ENVIRONMENT, JOB_NAME).newBuilder())
+ .setCronSchedule("1 1 1 1 1")
+ .setTaskConfig(defaultTask())
+ .setInstanceCount(1));
+ }
+
+ private static TaskConfig defaultTask() {
+ return new TaskConfig()
+ .setContactEmail("testing@twitter.com")
+ .setExecutorConfig(new ExecutorConfig("aurora", "data"))
+ .setNumCpus(1)
+ .setRamMb(1024)
+ .setDiskMb(1024)
+ .setJobName(JOB_NAME)
+ .setOwner(new Identity(OWNER, OWNER))
+ .setEnvironment(DEFAULT_ENVIRONMENT);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/state/LockManagerImplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/state/LockManagerImplTest.java b/src/test/java/org/apache/aurora/scheduler/state/LockManagerImplTest.java
index cdb1f5d..c8ad55d 100644
--- a/src/test/java/org/apache/aurora/scheduler/state/LockManagerImplTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/state/LockManagerImplTest.java
@@ -133,6 +133,6 @@ public class LockManagerImplTest extends EasyMockTest {
private void expectLockException(IJobKey key) {
expectedException.expect(LockException.class);
- expectedException.expectMessage(JobKeys.canonicalString(key));
+ expectedException.expectMessage(JobKeys.toPath(key));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
index f761feb..f530c53 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
@@ -76,13 +76,10 @@ import org.apache.aurora.scheduler.base.Query;
import org.apache.aurora.scheduler.base.ScheduleException;
import org.apache.aurora.scheduler.configuration.ConfigurationManager;
import org.apache.aurora.scheduler.configuration.SanitizedConfiguration;
-import org.apache.aurora.scheduler.cron.CronException;
-import org.apache.aurora.scheduler.cron.CronJobManager;
import org.apache.aurora.scheduler.cron.CronPredictor;
-import org.apache.aurora.scheduler.cron.CrontabEntry;
-import org.apache.aurora.scheduler.cron.SanitizedCronJob;
import org.apache.aurora.scheduler.quota.QuotaInfo;
import org.apache.aurora.scheduler.quota.QuotaManager;
+import org.apache.aurora.scheduler.state.CronJobManager;
import org.apache.aurora.scheduler.state.LockManager;
import org.apache.aurora.scheduler.state.LockManager.LockException;
import org.apache.aurora.scheduler.state.MaintenanceController;
@@ -138,7 +135,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
private static final IJobKey JOB_KEY = JobKeys.from(ROLE, DEFAULT_ENVIRONMENT, JOB_NAME);
private static final ILockKey LOCK_KEY = ILockKey.build(LockKey.job(JOB_KEY.newBuilder()));
private static final ILock LOCK = ILock.build(new Lock().setKey(LOCK_KEY.newBuilder()));
- private static final JobConfiguration CRON_JOB = makeJob().setCronSchedule("* * * * *");
+ private static final JobConfiguration CRON_JOB = makeJob().setCronSchedule("test");
private static final Lock DEFAULT_LOCK = null;
private static final IResourceAggregate QUOTA =
@@ -669,7 +666,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
public void testReplaceCronTemplate() throws Exception {
expectAuth(ROLE, true);
lockManager.validateIfLocked(LOCK_KEY, Optional.<ILock>absent());
- cronJobManager.updateJob(anyObject(SanitizedCronJob.class));
+ cronJobManager.updateJob(anyObject(SanitizedConfiguration.class));
control.replay();
assertEquals(
@@ -704,9 +701,9 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
public void testReplaceCronTemplateDoesNotExist() throws Exception {
expectAuth(ROLE, true);
lockManager.validateIfLocked(LOCK_KEY, Optional.<ILock>absent());
- cronJobManager.updateJob(anyObject(SanitizedCronJob.class));
- expectLastCall().andThrow(new CronException("Nope"));
-
+ cronJobManager.updateJob(
+ SanitizedConfiguration.fromUnsanitized(IJobConfiguration.build(CRON_JOB)));
+ expectLastCall().andThrow(new ScheduleException("Nope"));
control.replay();
assertEquals(
@@ -1011,7 +1008,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
Set<JobSummary> ownedImmedieteJobSummaryOnly = ImmutableSet.of(
new JobSummary().setJob(ownedImmediateJob).setStats(new JobStats().setActiveTaskCount(1)));
- expect(cronPredictor.predictNextRun(CrontabEntry.parse(CRON_SCHEDULE)))
+ expect(cronPredictor.predictNextRun(CRON_SCHEDULE))
.andReturn(new Date(nextCronRunMs))
.anyTimes();
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/thrift/ThriftIT.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/ThriftIT.java b/src/test/java/org/apache/aurora/scheduler/thrift/ThriftIT.java
index 8673330..e212174 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/ThriftIT.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/ThriftIT.java
@@ -34,8 +34,8 @@ import org.apache.aurora.gen.AuroraAdmin;
import org.apache.aurora.gen.ResourceAggregate;
import org.apache.aurora.gen.ServerInfo;
import org.apache.aurora.gen.SessionKey;
-import org.apache.aurora.scheduler.cron.CronJobManager;
import org.apache.aurora.scheduler.cron.CronPredictor;
+import org.apache.aurora.scheduler.cron.CronScheduler;
import org.apache.aurora.scheduler.quota.QuotaManager;
import org.apache.aurora.scheduler.state.LockManager;
import org.apache.aurora.scheduler.state.MaintenanceController;
@@ -149,7 +149,7 @@ public class ThriftIT extends EasyMockTest {
@Override
protected void configure() {
- bindMock(CronJobManager.class);
+ bindMock(CronScheduler.class);
bindMock(MaintenanceController.class);
bindMock(Recovery.class);
bindMock(SchedulerCore.class);
[3/5] Revert "AURORA-132: Cron system based on Quartz"
Posted by ke...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/main/resources/org/apache/aurora/scheduler/cron/testing/cron-schedule-predictions.json
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/aurora/scheduler/cron/testing/cron-schedule-predictions.json b/src/main/resources/org/apache/aurora/scheduler/cron/testing/cron-schedule-predictions.json
new file mode 100644
index 0000000..dced8b4
--- /dev/null
+++ b/src/main/resources/org/apache/aurora/scheduler/cron/testing/cron-schedule-predictions.json
@@ -0,0 +1,3332 @@
+[
+ {
+ "schedule": "0 20 * * 1",
+ "triggerTimes": [
+ 417600000,
+ 1022400000,
+ 1627200000,
+ 2232000000,
+ 2836800000,
+ 3441600000,
+ 4046400000,
+ 4651200000,
+ 5256000000,
+ 5860800000
+ ]
+ },
+ {
+ "schedule": "11 * * * *",
+ "triggerTimes": [
+ 660000,
+ 4260000,
+ 7860000,
+ 11460000,
+ 15060000,
+ 18660000,
+ 22260000,
+ 25860000,
+ 29460000,
+ 33060000
+ ]
+ },
+ {
+ "schedule": "04 02 * * *",
+ "triggerTimes": [
+ 7440000,
+ 93840000,
+ 180240000,
+ 266640000,
+ 353040000,
+ 439440000,
+ 525840000,
+ 612240000,
+ 698640000,
+ 785040000
+ ]
+ },
+ {
+ "schedule": "09 22 * * *",
+ "triggerTimes": [
+ 79740000,
+ 166140000,
+ 252540000,
+ 338940000,
+ 425340000,
+ 511740000,
+ 598140000,
+ 684540000,
+ 770940000,
+ 857340000
+ ]
+ },
+ {
+ "schedule": "1-56/5 * * * *",
+ "triggerTimes": [
+ 60000,
+ 360000,
+ 660000,
+ 960000,
+ 1260000,
+ 1560000,
+ 1860000,
+ 2160000,
+ 2460000,
+ 2760000
+ ]
+ },
+ {
+ "schedule": "05 02,08,12 * * *",
+ "triggerTimes": [
+ 7500000,
+ 29100000,
+ 43500000,
+ 93900000,
+ 115500000,
+ 129900000,
+ 180300000,
+ 201900000,
+ 216300000,
+ 266700000
+ ]
+ },
+ {
+ "schedule": "26 * * * *",
+ "triggerTimes": [
+ 1560000,
+ 5160000,
+ 8760000,
+ 12360000,
+ 15960000,
+ 19560000,
+ 23160000,
+ 26760000,
+ 30360000,
+ 33960000
+ ]
+ },
+ {
+ "schedule": "3,43 * * * *",
+ "triggerTimes": [
+ 180000,
+ 2580000,
+ 3780000,
+ 6180000,
+ 7380000,
+ 9780000,
+ 10980000,
+ 13380000,
+ 14580000,
+ 16980000
+ ]
+ },
+ {
+ "schedule": "0 17-23 * * 1-5",
+ "triggerTimes": [
+ 61200000,
+ 64800000,
+ 68400000,
+ 72000000,
+ 75600000,
+ 79200000,
+ 82800000,
+ 147600000,
+ 151200000,
+ 154800000
+ ]
+ },
+ {
+ "schedule": "0 0,12 * * *",
+ "triggerTimes": [
+ 43200000,
+ 86400000,
+ 129600000,
+ 172800000,
+ 216000000,
+ 259200000,
+ 302400000,
+ 345600000,
+ 388800000,
+ 432000000
+ ]
+ },
+ {
+ "schedule": "10 02,08,12 * * *",
+ "triggerTimes": [
+ 7800000,
+ 29400000,
+ 43800000,
+ 94200000,
+ 115800000,
+ 130200000,
+ 180600000,
+ 202200000,
+ 216600000,
+ 267000000
+ ]
+ },
+ {
+ "schedule": "50 */4 * * *",
+ "triggerTimes": [
+ 3000000,
+ 17400000,
+ 31800000,
+ 46200000,
+ 60600000,
+ 75000000,
+ 89400000,
+ 103800000,
+ 118200000,
+ 132600000
+ ]
+ },
+ {
+ "schedule": "10 02,08,14,20 * * *",
+ "triggerTimes": [
+ 7800000,
+ 29400000,
+ 51000000,
+ 72600000,
+ 94200000,
+ 115800000,
+ 137400000,
+ 159000000,
+ 180600000,
+ 202200000
+ ]
+ },
+ {
+ "schedule": "0 */6 * * *",
+ "triggerTimes": [
+ 21600000,
+ 43200000,
+ 64800000,
+ 86400000,
+ 108000000,
+ 129600000,
+ 151200000,
+ 172800000,
+ 194400000,
+ 216000000
+ ]
+ },
+ {
+ "schedule": "* * * * *",
+ "triggerTimes": [
+ 60000,
+ 120000,
+ 180000,
+ 240000,
+ 300000,
+ 360000,
+ 420000,
+ 480000,
+ 540000,
+ 600000
+ ]
+ },
+ {
+ "schedule": "30 15 * * *,",
+ "triggerTimes": [
+ 55800000,
+ 142200000,
+ 228600000,
+ 315000000,
+ 401400000,
+ 487800000,
+ 574200000,
+ 660600000,
+ 747000000,
+ 833400000
+ ]
+ },
+ {
+ "schedule": "00 11 * * *",
+ "triggerTimes": [
+ 39600000,
+ 126000000,
+ 212400000,
+ 298800000,
+ 385200000,
+ 471600000,
+ 558000000,
+ 644400000,
+ 730800000,
+ 817200000
+ ]
+ },
+ {
+ "schedule": "55 06 * * *",
+ "triggerTimes": [
+ 24900000,
+ 111300000,
+ 197700000,
+ 284100000,
+ 370500000,
+ 456900000,
+ 543300000,
+ 629700000,
+ 716100000,
+ 802500000
+ ]
+ },
+ {
+ "schedule": "0 4 * * *",
+ "triggerTimes": [
+ 14400000,
+ 100800000,
+ 187200000,
+ 273600000,
+ 360000000,
+ 446400000,
+ 532800000,
+ 619200000,
+ 705600000,
+ 792000000
+ ]
+ },
+ {
+ "schedule": "55 */1 * * *",
+ "triggerTimes": [
+ 3300000,
+ 6900000,
+ 10500000,
+ 14100000,
+ 17700000,
+ 21300000,
+ 24900000,
+ 28500000,
+ 32100000,
+ 35700000
+ ]
+ },
+ {
+ "schedule": "15 */3 * * *",
+ "triggerTimes": [
+ 900000,
+ 11700000,
+ 22500000,
+ 33300000,
+ 44100000,
+ 54900000,
+ 65700000,
+ 76500000,
+ 87300000,
+ 98100000
+ ]
+ },
+ {
+ "schedule": "42 8,12,16 * * *",
+ "triggerTimes": [
+ 31320000,
+ 45720000,
+ 60120000,
+ 117720000,
+ 132120000,
+ 146520000,
+ 204120000,
+ 218520000,
+ 232920000,
+ 290520000
+ ]
+ },
+ {
+ "schedule": "23 * * * *",
+ "triggerTimes": [
+ 1380000,
+ 4980000,
+ 8580000,
+ 12180000,
+ 15780000,
+ 19380000,
+ 22980000,
+ 26580000,
+ 30180000,
+ 33780000
+ ]
+ },
+ {
+ "schedule": "10 16 * * *",
+ "triggerTimes": [
+ 58200000,
+ 144600000,
+ 231000000,
+ 317400000,
+ 403800000,
+ 490200000,
+ 576600000,
+ 663000000,
+ 749400000,
+ 835800000
+ ]
+ },
+ {
+ "schedule": "*/30 * * * *",
+ "triggerTimes": [
+ 1800000,
+ 3600000,
+ 5400000,
+ 7200000,
+ 9000000,
+ 10800000,
+ 12600000,
+ 14400000,
+ 16200000,
+ 18000000
+ ]
+ },
+ {
+ "schedule": "20 */3 * * *",
+ "triggerTimes": [
+ 1200000,
+ 12000000,
+ 22800000,
+ 33600000,
+ 44400000,
+ 55200000,
+ 66000000,
+ 76800000,
+ 87600000,
+ 98400000
+ ]
+ },
+ {
+ "schedule": "8 6,12,18 * * *",
+ "triggerTimes": [
+ 22080000,
+ 43680000,
+ 65280000,
+ 108480000,
+ 130080000,
+ 151680000,
+ 194880000,
+ 216480000,
+ 238080000,
+ 281280000
+ ]
+ },
+ {
+ "schedule": "30 7,12,22 * * *",
+ "triggerTimes": [
+ 27000000,
+ 45000000,
+ 81000000,
+ 113400000,
+ 131400000,
+ 167400000,
+ 199800000,
+ 217800000,
+ 253800000,
+ 286200000
+ ]
+ },
+ {
+ "schedule": "0 0 12 * *",
+ "triggerTimes": [
+ 950400000,
+ 3628800000,
+ 6048000000,
+ 8726400000,
+ 11318400000,
+ 13996800000,
+ 16588800000,
+ 19267200000,
+ 21945600000,
+ 24537600000
+ ]
+ },
+ {
+ "schedule": "17 5,8,13,16,19 * * *",
+ "triggerTimes": [
+ 19020000,
+ 29820000,
+ 47820000,
+ 58620000,
+ 69420000,
+ 105420000,
+ 116220000,
+ 134220000,
+ 145020000,
+ 155820000
+ ]
+ },
+ {
+ "schedule": "27 8,20 * * *",
+ "triggerTimes": [
+ 30420000,
+ 73620000,
+ 116820000,
+ 160020000,
+ 203220000,
+ 246420000,
+ 289620000,
+ 332820000,
+ 376020000,
+ 419220000
+ ]
+ },
+ {
+ "schedule": "15 */6 * * *",
+ "triggerTimes": [
+ 900000,
+ 22500000,
+ 44100000,
+ 65700000,
+ 87300000,
+ 108900000,
+ 130500000,
+ 152100000,
+ 173700000,
+ 195300000
+ ]
+ },
+ {
+ "schedule": "01 15 * * *",
+ "triggerTimes": [
+ 54060000,
+ 140460000,
+ 226860000,
+ 313260000,
+ 399660000,
+ 486060000,
+ 572460000,
+ 658860000,
+ 745260000,
+ 831660000
+ ]
+ },
+ {
+ "schedule": "0 18 * * *",
+ "triggerTimes": [
+ 64800000,
+ 151200000,
+ 237600000,
+ 324000000,
+ 410400000,
+ 496800000,
+ 583200000,
+ 669600000,
+ 756000000,
+ 842400000
+ ]
+ },
+ {
+ "schedule": "24 * * * *",
+ "triggerTimes": [
+ 1440000,
+ 5040000,
+ 8640000,
+ 12240000,
+ 15840000,
+ 19440000,
+ 23040000,
+ 26640000,
+ 30240000,
+ 33840000
+ ]
+ },
+ {
+ "schedule": "18 00 * * *",
+ "triggerTimes": [
+ 1080000,
+ 87480000,
+ 173880000,
+ 260280000,
+ 346680000,
+ 433080000,
+ 519480000,
+ 605880000,
+ 692280000,
+ 778680000
+ ]
+ },
+ {
+ "schedule": "0 16 * * *",
+ "triggerTimes": [
+ 57600000,
+ 144000000,
+ 230400000,
+ 316800000,
+ 403200000,
+ 489600000,
+ 576000000,
+ 662400000,
+ 748800000,
+ 835200000
+ ]
+ },
+ {
+ "schedule": "45 5 * * *",
+ "triggerTimes": [
+ 20700000,
+ 107100000,
+ 193500000,
+ 279900000,
+ 366300000,
+ 452700000,
+ 539100000,
+ 625500000,
+ 711900000,
+ 798300000
+ ]
+ },
+ {
+ "schedule": "0 18 * * 4",
+ "triggerTimes": [
+ 64800000,
+ 669600000,
+ 1274400000,
+ 1879200000,
+ 2484000000,
+ 3088800000,
+ 3693600000,
+ 4298400000,
+ 4903200000,
+ 5508000000
+ ]
+ },
+ {
+ "schedule": "30 19 * * *",
+ "triggerTimes": [
+ 70200000,
+ 156600000,
+ 243000000,
+ 329400000,
+ 415800000,
+ 502200000,
+ 588600000,
+ 675000000,
+ 761400000,
+ 847800000
+ ]
+ },
+ {
+ "schedule": "0 13 * * 2",
+ "triggerTimes": [
+ 478800000,
+ 1083600000,
+ 1688400000,
+ 2293200000,
+ 2898000000,
+ 3502800000,
+ 4107600000,
+ 4712400000,
+ 5317200000,
+ 5922000000
+ ]
+ },
+ {
+ "schedule": "25 17,20,21,23 * * *",
+ "triggerTimes": [
+ 62700000,
+ 73500000,
+ 77100000,
+ 84300000,
+ 149100000,
+ 159900000,
+ 163500000,
+ 170700000,
+ 235500000,
+ 246300000
+ ]
+ },
+ {
+ "schedule": "0 13 * * 3",
+ "triggerTimes": [
+ 565200000,
+ 1170000000,
+ 1774800000,
+ 2379600000,
+ 2984400000,
+ 3589200000,
+ 4194000000,
+ 4798800000,
+ 5403600000,
+ 6008400000
+ ]
+ },
+ {
+ "schedule": "58 */2 * * *",
+ "triggerTimes": [
+ 3480000,
+ 10680000,
+ 17880000,
+ 25080000,
+ 32280000,
+ 39480000,
+ 46680000,
+ 53880000,
+ 61080000,
+ 68280000
+ ]
+ },
+ {
+ "schedule": "0 9 4,18 * *",
+ "triggerTimes": [
+ 291600000,
+ 1501200000,
+ 2970000000,
+ 4179600000,
+ 5389200000,
+ 6598800000,
+ 8067600000,
+ 9277200000,
+ 10659600000,
+ 11869200000
+ ]
+ },
+ {
+ "schedule": "37 */6 * * *",
+ "triggerTimes": [
+ 2220000,
+ 23820000,
+ 45420000,
+ 67020000,
+ 88620000,
+ 110220000,
+ 131820000,
+ 153420000,
+ 175020000,
+ 196620000
+ ]
+ },
+ {
+ "schedule": "00 14 * * *",
+ "triggerTimes": [
+ 50400000,
+ 136800000,
+ 223200000,
+ 309600000,
+ 396000000,
+ 482400000,
+ 568800000,
+ 655200000,
+ 741600000,
+ 828000000
+ ]
+ },
+ {
+ "schedule": "0 * * * *",
+ "triggerTimes": [
+ 3600000,
+ 7200000,
+ 10800000,
+ 14400000,
+ 18000000,
+ 21600000,
+ 25200000,
+ 28800000,
+ 32400000,
+ 36000000
+ ]
+ },
+ {
+ "schedule": "29 9,16,22 * * *",
+ "triggerTimes": [
+ 34140000,
+ 59340000,
+ 80940000,
+ 120540000,
+ 145740000,
+ 167340000,
+ 206940000,
+ 232140000,
+ 253740000,
+ 293340000
+ ]
+ },
+ {
+ "schedule": "37 3 * * *",
+ "triggerTimes": [
+ 13020000,
+ 99420000,
+ 185820000,
+ 272220000,
+ 358620000,
+ 445020000,
+ 531420000,
+ 617820000,
+ 704220000,
+ 790620000
+ ]
+ },
+ {
+ "schedule": "*/5 * * * *",
+ "triggerTimes": [
+ 300000,
+ 600000,
+ 900000,
+ 1200000,
+ 1500000,
+ 1800000,
+ 2100000,
+ 2400000,
+ 2700000,
+ 3000000
+ ]
+ },
+ {
+ "schedule": "7 */2 * * *",
+ "triggerTimes": [
+ 420000,
+ 7620000,
+ 14820000,
+ 22020000,
+ 29220000,
+ 36420000,
+ 43620000,
+ 50820000,
+ 58020000,
+ 65220000
+ ]
+ },
+ {
+ "schedule": "55 07 * * *",
+ "triggerTimes": [
+ 28500000,
+ 114900000,
+ 201300000,
+ 287700000,
+ 374100000,
+ 460500000,
+ 546900000,
+ 633300000,
+ 719700000,
+ 806100000
+ ]
+ },
+ {
+ "schedule": "0 19 * * *",
+ "triggerTimes": [
+ 68400000,
+ 154800000,
+ 241200000,
+ 327600000,
+ 414000000,
+ 500400000,
+ 586800000,
+ 673200000,
+ 759600000,
+ 846000000
+ ]
+ },
+ {
+ "schedule": "15 */2 * * *",
+ "triggerTimes": [
+ 900000,
+ 8100000,
+ 15300000,
+ 22500000,
+ 29700000,
+ 36900000,
+ 44100000,
+ 51300000,
+ 58500000,
+ 65700000
+ ]
+ },
+ {
+ "schedule": "17 00 * * *",
+ "triggerTimes": [
+ 1020000,
+ 87420000,
+ 173820000,
+ 260220000,
+ 346620000,
+ 433020000,
+ 519420000,
+ 605820000,
+ 692220000,
+ 778620000
+ ]
+ },
+ {
+ "schedule": "0 0 * * 1",
+ "triggerTimes": [
+ 345600000,
+ 950400000,
+ 1555200000,
+ 2160000000,
+ 2764800000,
+ 3369600000,
+ 3974400000,
+ 4579200000,
+ 5184000000,
+ 5788800000
+ ]
+ },
+ {
+ "schedule": "29 */4 * * *",
+ "triggerTimes": [
+ 1740000,
+ 16140000,
+ 30540000,
+ 44940000,
+ 59340000,
+ 73740000,
+ 88140000,
+ 102540000,
+ 116940000,
+ 131340000
+ ]
+ },
+ {
+ "schedule": "0 23 * * *",
+ "triggerTimes": [
+ 82800000,
+ 169200000,
+ 255600000,
+ 342000000,
+ 428400000,
+ 514800000,
+ 601200000,
+ 687600000,
+ 774000000,
+ 860400000
+ ]
+ },
+ {
+ "schedule": "0 7 * * *",
+ "triggerTimes": [
+ 25200000,
+ 111600000,
+ 198000000,
+ 284400000,
+ 370800000,
+ 457200000,
+ 543600000,
+ 630000000,
+ 716400000,
+ 802800000
+ ]
+ },
+ {
+ "schedule": "12 * * * *",
+ "triggerTimes": [
+ 720000,
+ 4320000,
+ 7920000,
+ 11520000,
+ 15120000,
+ 18720000,
+ 22320000,
+ 25920000,
+ 29520000,
+ 33120000
+ ]
+ },
+ {
+ "schedule": "0 23 * * 3",
+ "triggerTimes": [
+ 601200000,
+ 1206000000,
+ 1810800000,
+ 2415600000,
+ 3020400000,
+ 3625200000,
+ 4230000000,
+ 4834800000,
+ 5439600000,
+ 6044400000
+ ]
+ },
+ {
+ "schedule": "23 */4 * * *",
+ "triggerTimes": [
+ 1380000,
+ 15780000,
+ 30180000,
+ 44580000,
+ 58980000,
+ 73380000,
+ 87780000,
+ 102180000,
+ 116580000,
+ 130980000
+ ]
+ },
+ {
+ "schedule": "30 1-23/2 * * *",
+ "triggerTimes": [
+ 5400000,
+ 12600000,
+ 19800000,
+ 27000000,
+ 34200000,
+ 41400000,
+ 48600000,
+ 55800000,
+ 63000000,
+ 70200000
+ ]
+ },
+ {
+ "schedule": "5,15,25,35,45,55 * * * *",
+ "triggerTimes": [
+ 300000,
+ 900000,
+ 1500000,
+ 2100000,
+ 2700000,
+ 3300000,
+ 3900000,
+ 4500000,
+ 5100000,
+ 5700000
+ ]
+ },
+ {
+ "schedule": "23 1,11,21 * * *",
+ "triggerTimes": [
+ 4980000,
+ 40980000,
+ 76980000,
+ 91380000,
+ 127380000,
+ 163380000,
+ 177780000,
+ 213780000,
+ 249780000,
+ 264180000
+ ]
+ },
+ {
+ "schedule": "15 04,10,16,22 * * *",
+ "triggerTimes": [
+ 15300000,
+ 36900000,
+ 58500000,
+ 80100000,
+ 101700000,
+ 123300000,
+ 144900000,
+ 166500000,
+ 188100000,
+ 209700000
+ ]
+ },
+ {
+ "schedule": "*/20 * * * *",
+ "triggerTimes": [
+ 1200000,
+ 2400000,
+ 3600000,
+ 4800000,
+ 6000000,
+ 7200000,
+ 8400000,
+ 9600000,
+ 10800000,
+ 12000000
+ ]
+ },
+ {
+ "schedule": "12,42 * * * *",
+ "triggerTimes": [
+ 720000,
+ 2520000,
+ 4320000,
+ 6120000,
+ 7920000,
+ 9720000,
+ 11520000,
+ 13320000,
+ 15120000,
+ 16920000
+ ]
+ },
+ {
+ "schedule": "26 2,6,10,14,18,22 * * *",
+ "triggerTimes": [
+ 8760000,
+ 23160000,
+ 37560000,
+ 51960000,
+ 66360000,
+ 80760000,
+ 95160000,
+ 109560000,
+ 123960000,
+ 138360000
+ ]
+ },
+ {
+ "schedule": "0 3,6,9,12,15,18,21 * * *",
+ "triggerTimes": [
+ 10800000,
+ 21600000,
+ 32400000,
+ 43200000,
+ 54000000,
+ 64800000,
+ 75600000,
+ 97200000,
+ 108000000,
+ 118800000
+ ]
+ },
+ {
+ "schedule": "25 14 * * *",
+ "triggerTimes": [
+ 51900000,
+ 138300000,
+ 224700000,
+ 311100000,
+ 397500000,
+ 483900000,
+ 570300000,
+ 656700000,
+ 743100000,
+ 829500000
+ ]
+ },
+ {
+ "schedule": "0 5 * * *,",
+ "triggerTimes": [
+ 18000000,
+ 104400000,
+ 190800000,
+ 277200000,
+ 363600000,
+ 450000000,
+ 536400000,
+ 622800000,
+ 709200000,
+ 795600000
+ ]
+ },
+ {
+ "schedule": "43 * * * *",
+ "triggerTimes": [
+ 2580000,
+ 6180000,
+ 9780000,
+ 13380000,
+ 16980000,
+ 20580000,
+ 24180000,
+ 27780000,
+ 31380000,
+ 34980000
+ ]
+ },
+ {
+ "schedule": "39 6,12,16 * * *",
+ "triggerTimes": [
+ 23940000,
+ 45540000,
+ 59940000,
+ 110340000,
+ 131940000,
+ 146340000,
+ 196740000,
+ 218340000,
+ 232740000,
+ 283140000
+ ]
+ },
+ {
+ "schedule": "0 9 1 * *",
+ "triggerTimes": [
+ 32400000,
+ 2710800000,
+ 5130000000,
+ 7808400000,
+ 10400400000,
+ 13078800000,
+ 15670800000,
+ 18349200000,
+ 21027600000,
+ 23619600000
+ ]
+ },
+ {
+ "schedule": "14-59/30 * * * *",
+ "triggerTimes": [
+ 840000,
+ 2640000,
+ 4440000,
+ 6240000,
+ 8040000,
+ 9840000,
+ 11640000,
+ 13440000,
+ 15240000,
+ 17040000
+ ]
+ },
+ {
+ "schedule": "0 0 * * *",
+ "triggerTimes": [
+ 86400000,
+ 172800000,
+ 259200000,
+ 345600000,
+ 432000000,
+ 518400000,
+ 604800000,
+ 691200000,
+ 777600000,
+ 864000000
+ ]
+ },
+ {
+ "schedule": "0 */3 * * *",
+ "triggerTimes": [
+ 10800000,
+ 21600000,
+ 32400000,
+ 43200000,
+ 54000000,
+ 64800000,
+ 75600000,
+ 86400000,
+ 97200000,
+ 108000000
+ ]
+ },
+ {
+ "schedule": "16 5,13,21 * * *",
+ "triggerTimes": [
+ 18960000,
+ 47760000,
+ 76560000,
+ 105360000,
+ 134160000,
+ 162960000,
+ 191760000,
+ 220560000,
+ 249360000,
+ 278160000
+ ]
+ },
+ {
+ "schedule": "30 18,23 * * MON-FRI",
+ "triggerTimes": [
+ 66600000,
+ 84600000,
+ 153000000,
+ 171000000,
+ 412200000,
+ 430200000,
+ 498600000,
+ 516600000,
+ 585000000,
+ 603000000
+ ]
+ },
+ {
+ "schedule": "0,15,30,45 * * * *",
+ "triggerTimes": [
+ 900000,
+ 1800000,
+ 2700000,
+ 3600000,
+ 4500000,
+ 5400000,
+ 6300000,
+ 7200000,
+ 8100000,
+ 9000000
+ ]
+ },
+ {
+ "schedule": "42 8,20 * * *",
+ "triggerTimes": [
+ 31320000,
+ 74520000,
+ 117720000,
+ 160920000,
+ 204120000,
+ 247320000,
+ 290520000,
+ 333720000,
+ 376920000,
+ 420120000
+ ]
+ },
+ {
+ "schedule": "46 */6 * * *",
+ "triggerTimes": [
+ 2760000,
+ 24360000,
+ 45960000,
+ 67560000,
+ 89160000,
+ 110760000,
+ 132360000,
+ 153960000,
+ 175560000,
+ 197160000
+ ]
+ },
+ {
+ "schedule": "0 3 * * *",
+ "triggerTimes": [
+ 10800000,
+ 97200000,
+ 183600000,
+ 270000000,
+ 356400000,
+ 442800000,
+ 529200000,
+ 615600000,
+ 702000000,
+ 788400000
+ ]
+ },
+ {
+ "schedule": "16 9,16 * * *",
+ "triggerTimes": [
+ 33360000,
+ 58560000,
+ 119760000,
+ 144960000,
+ 206160000,
+ 231360000,
+ 292560000,
+ 317760000,
+ 378960000,
+ 404160000
+ ]
+ },
+ {
+ "schedule": "15 0 * * *",
+ "triggerTimes": [
+ 900000,
+ 87300000,
+ 173700000,
+ 260100000,
+ 346500000,
+ 432900000,
+ 519300000,
+ 605700000,
+ 692100000,
+ 778500000
+ ]
+ },
+ {
+ "schedule": "05 * * * *",
+ "triggerTimes": [
+ 300000,
+ 3900000,
+ 7500000,
+ 11100000,
+ 14700000,
+ 18300000,
+ 21900000,
+ 25500000,
+ 29100000,
+ 32700000
+ ]
+ },
+ {
+ "schedule": "30 * * * *",
+ "triggerTimes": [
+ 1800000,
+ 5400000,
+ 9000000,
+ 12600000,
+ 16200000,
+ 19800000,
+ 23400000,
+ 27000000,
+ 30600000,
+ 34200000
+ ]
+ },
+ {
+ "schedule": "0 2,14 * * *",
+ "triggerTimes": [
+ 7200000,
+ 50400000,
+ 93600000,
+ 136800000,
+ 180000000,
+ 223200000,
+ 266400000,
+ 309600000,
+ 352800000,
+ 396000000
+ ]
+ },
+ {
+ "schedule": "28 23 * * 3",
+ "triggerTimes": [
+ 602880000,
+ 1207680000,
+ 1812480000,
+ 2417280000,
+ 3022080000,
+ 3626880000,
+ 4231680000,
+ 4836480000,
+ 5441280000,
+ 6046080000
+ ]
+ },
+ {
+ "schedule": "5 */4 * * *",
+ "triggerTimes": [
+ 300000,
+ 14700000,
+ 29100000,
+ 43500000,
+ 57900000,
+ 72300000,
+ 86700000,
+ 101100000,
+ 115500000,
+ 129900000
+ ]
+ },
+ {
+ "schedule": "0 18,22 * * MON-FRI",
+ "triggerTimes": [
+ 64800000,
+ 79200000,
+ 151200000,
+ 165600000,
+ 410400000,
+ 424800000,
+ 496800000,
+ 511200000,
+ 583200000,
+ 597600000
+ ]
+ },
+ {
+ "schedule": "01 21 * * *",
+ "triggerTimes": [
+ 75660000,
+ 162060000,
+ 248460000,
+ 334860000,
+ 421260000,
+ 507660000,
+ 594060000,
+ 680460000,
+ 766860000,
+ 853260000
+ ]
+ },
+ {
+ "schedule": "1 */6 * * *",
+ "triggerTimes": [
+ 60000,
+ 21660000,
+ 43260000,
+ 64860000,
+ 86460000,
+ 108060000,
+ 129660000,
+ 151260000,
+ 172860000,
+ 194460000
+ ]
+ },
+ {
+ "schedule": "*/10 * * * *",
+ "triggerTimes": [
+ 600000,
+ 1200000,
+ 1800000,
+ 2400000,
+ 3000000,
+ 3600000,
+ 4200000,
+ 4800000,
+ 5400000,
+ 6000000
+ ]
+ },
+ {
+ "schedule": "44 */2 * * *",
+ "triggerTimes": [
+ 2640000,
+ 9840000,
+ 17040000,
+ 24240000,
+ 31440000,
+ 38640000,
+ 45840000,
+ 53040000,
+ 60240000,
+ 67440000
+ ]
+ },
+ {
+ "schedule": "30 2 * * *",
+ "triggerTimes": [
+ 9000000,
+ 95400000,
+ 181800000,
+ 268200000,
+ 354600000,
+ 441000000,
+ 527400000,
+ 613800000,
+ 700200000,
+ 786600000
+ ]
+ },
+ {
+ "schedule": "58 * * * *",
+ "triggerTimes": [
+ 3480000,
+ 7080000,
+ 10680000,
+ 14280000,
+ 17880000,
+ 21480000,
+ 25080000,
+ 28680000,
+ 32280000,
+ 35880000
+ ]
+ },
+ {
+ "schedule": "30 23 * * 6",
+ "triggerTimes": [
+ 257400000,
+ 862200000,
+ 1467000000,
+ 2071800000,
+ 2676600000,
+ 3281400000,
+ 3886200000,
+ 4491000000,
+ 5095800000,
+ 5700600000
+ ]
+ },
+ {
+ "schedule": "40 23 * * *",
+ "triggerTimes": [
+ 85200000,
+ 171600000,
+ 258000000,
+ 344400000,
+ 430800000,
+ 517200000,
+ 603600000,
+ 690000000,
+ 776400000,
+ 862800000
+ ]
+ },
+ {
+ "schedule": "0 5,10,15,20,1 * * *",
+ "triggerTimes": [
+ 3600000,
+ 18000000,
+ 36000000,
+ 54000000,
+ 72000000,
+ 90000000,
+ 104400000,
+ 122400000,
+ 140400000,
+ 158400000
+ ]
+ },
+ {
+ "schedule": "22 * * * *",
+ "triggerTimes": [
+ 1320000,
+ 4920000,
+ 8520000,
+ 12120000,
+ 15720000,
+ 19320000,
+ 22920000,
+ 26520000,
+ 30120000,
+ 33720000
+ ]
+ },
+ {
+ "schedule": "00 17 1-3,5-31 * *",
+ "triggerTimes": [
+ 61200000,
+ 147600000,
+ 234000000,
+ 406800000,
+ 493200000,
+ 579600000,
+ 666000000,
+ 752400000,
+ 838800000,
+ 925200000
+ ]
+ },
+ {
+ "schedule": "0 2 1 * *",
+ "triggerTimes": [
+ 7200000,
+ 2685600000,
+ 5104800000,
+ 7783200000,
+ 10375200000,
+ 13053600000,
+ 15645600000,
+ 18324000000,
+ 21002400000,
+ 23594400000
+ ]
+ },
+ {
+ "schedule": "20 20 * * *",
+ "triggerTimes": [
+ 73200000,
+ 159600000,
+ 246000000,
+ 332400000,
+ 418800000,
+ 505200000,
+ 591600000,
+ 678000000,
+ 764400000,
+ 850800000
+ ]
+ },
+ {
+ "schedule": "45 1 * * *",
+ "triggerTimes": [
+ 6300000,
+ 92700000,
+ 179100000,
+ 265500000,
+ 351900000,
+ 438300000,
+ 524700000,
+ 611100000,
+ 697500000,
+ 783900000
+ ]
+ },
+ {
+ "schedule": "3-59/5 * * * *",
+ "triggerTimes": [
+ 180000,
+ 480000,
+ 780000,
+ 1080000,
+ 1380000,
+ 1680000,
+ 1980000,
+ 2280000,
+ 2580000,
+ 2880000
+ ]
+ },
+ {
+ "schedule": "21 * * * *",
+ "triggerTimes": [
+ 1260000,
+ 4860000,
+ 8460000,
+ 12060000,
+ 15660000,
+ 19260000,
+ 22860000,
+ 26460000,
+ 30060000,
+ 33660000
+ ]
+ },
+ {
+ "schedule": "37 */1 * * *",
+ "triggerTimes": [
+ 2220000,
+ 5820000,
+ 9420000,
+ 13020000,
+ 16620000,
+ 20220000,
+ 23820000,
+ 27420000,
+ 31020000,
+ 34620000
+ ]
+ },
+ {
+ "schedule": "12 3 * * 1,3,5",
+ "triggerTimes": [
+ 97920000,
+ 357120000,
+ 529920000,
+ 702720000,
+ 961920000,
+ 1134720000,
+ 1307520000,
+ 1566720000,
+ 1739520000,
+ 1912320000
+ ]
+ },
+ {
+ "schedule": "10 * * * *",
+ "triggerTimes": [
+ 600000,
+ 4200000,
+ 7800000,
+ 11400000,
+ 15000000,
+ 18600000,
+ 22200000,
+ 25800000,
+ 29400000,
+ 33000000
+ ]
+ },
+ {
+ "schedule": "*/4 * * * *",
+ "triggerTimes": [
+ 240000,
+ 480000,
+ 720000,
+ 960000,
+ 1200000,
+ 1440000,
+ 1680000,
+ 1920000,
+ 2160000,
+ 2400000
+ ]
+ },
+ {
+ "schedule": "36 * * * *",
+ "triggerTimes": [
+ 2160000,
+ 5760000,
+ 9360000,
+ 12960000,
+ 16560000,
+ 20160000,
+ 23760000,
+ 27360000,
+ 30960000,
+ 34560000
+ ]
+ },
+ {
+ "schedule": "10 7 * * *",
+ "triggerTimes": [
+ 25800000,
+ 112200000,
+ 198600000,
+ 285000000,
+ 371400000,
+ 457800000,
+ 544200000,
+ 630600000,
+ 717000000,
+ 803400000
+ ]
+ },
+ {
+ "schedule": "55 6 * * *",
+ "triggerTimes": [
+ 24900000,
+ 111300000,
+ 197700000,
+ 284100000,
+ 370500000,
+ 456900000,
+ 543300000,
+ 629700000,
+ 716100000,
+ 802500000
+ ]
+ },
+ {
+ "schedule": "0 */2 * * *",
+ "triggerTimes": [
+ 7200000,
+ 14400000,
+ 21600000,
+ 28800000,
+ 36000000,
+ 43200000,
+ 50400000,
+ 57600000,
+ 64800000,
+ 72000000
+ ]
+ },
+ {
+ "schedule": "0 5 * * *",
+ "triggerTimes": [
+ 18000000,
+ 104400000,
+ 190800000,
+ 277200000,
+ 363600000,
+ 450000000,
+ 536400000,
+ 622800000,
+ 709200000,
+ 795600000
+ ]
+ },
+ {
+ "schedule": "22 */4 * * *",
+ "triggerTimes": [
+ 1320000,
+ 15720000,
+ 30120000,
+ 44520000,
+ 58920000,
+ 73320000,
+ 87720000,
+ 102120000,
+ 116520000,
+ 130920000
+ ]
+ },
+ {
+ "schedule": "17 */2 * * *",
+ "triggerTimes": [
+ 1020000,
+ 8220000,
+ 15420000,
+ 22620000,
+ 29820000,
+ 37020000,
+ 44220000,
+ 51420000,
+ 58620000,
+ 65820000
+ ]
+ },
+ {
+ "schedule": "25 * * * *",
+ "triggerTimes": [
+ 1500000,
+ 5100000,
+ 8700000,
+ 12300000,
+ 15900000,
+ 19500000,
+ 23100000,
+ 26700000,
+ 30300000,
+ 33900000
+ ]
+ },
+ {
+ "schedule": "*/6 * * * *",
+ "triggerTimes": [
+ 360000,
+ 720000,
+ 1080000,
+ 1440000,
+ 1800000,
+ 2160000,
+ 2520000,
+ 2880000,
+ 3240000,
+ 3600000
+ ]
+ },
+ {
+ "schedule": "5 * * * *",
+ "triggerTimes": [
+ 300000,
+ 3900000,
+ 7500000,
+ 11100000,
+ 14700000,
+ 18300000,
+ 21900000,
+ 25500000,
+ 29100000,
+ 32700000
+ ]
+ },
+ {
+ "schedule": "0 2 * * *",
+ "triggerTimes": [
+ 7200000,
+ 93600000,
+ 180000000,
+ 266400000,
+ 352800000,
+ 439200000,
+ 525600000,
+ 612000000,
+ 698400000,
+ 784800000
+ ]
+ },
+ {
+ "schedule": "0 * * * *",
+ "triggerTimes": [
+ 3600000,
+ 7200000,
+ 10800000,
+ 14400000,
+ 18000000,
+ 21600000,
+ 25200000,
+ 28800000,
+ 32400000,
+ 36000000
+ ]
+ },
+ {
+ "schedule": "0 14 * * *,,",
+ "triggerTimes": [
+ 50400000,
+ 136800000,
+ 223200000,
+ 309600000,
+ 396000000,
+ 482400000,
+ 568800000,
+ 655200000,
+ 741600000,
+ 828000000
+ ]
+ },
+ {
+ "schedule": "30 02,08,12 * * *",
+ "triggerTimes": [
+ 9000000,
+ 30600000,
+ 45000000,
+ 95400000,
+ 117000000,
+ 131400000,
+ 181800000,
+ 203400000,
+ 217800000,
+ 268200000
+ ]
+ },
+ {
+ "schedule": "44 23 * * *",
+ "triggerTimes": [
+ 85440000,
+ 171840000,
+ 258240000,
+ 344640000,
+ 431040000,
+ 517440000,
+ 603840000,
+ 690240000,
+ 776640000,
+ 863040000
+ ]
+ },
+ {
+ "schedule": "0 */4 * * *",
+ "triggerTimes": [
+ 14400000,
+ 28800000,
+ 43200000,
+ 57600000,
+ 72000000,
+ 86400000,
+ 100800000,
+ 115200000,
+ 129600000,
+ 144000000
+ ]
+ },
+ {
+ "schedule": "0 12 * * *",
+ "triggerTimes": [
+ 43200000,
+ 129600000,
+ 216000000,
+ 302400000,
+ 388800000,
+ 475200000,
+ 561600000,
+ 648000000,
+ 734400000,
+ 820800000
+ ]
+ },
+ {
+ "schedule": "*/2 * * * *",
+ "triggerTimes": [
+ 120000,
+ 240000,
+ 360000,
+ 480000,
+ 600000,
+ 720000,
+ 840000,
+ 960000,
+ 1080000,
+ 1200000
+ ]
+ },
+ {
+ "schedule": "22 1 * * *",
+ "triggerTimes": [
+ 4920000,
+ 91320000,
+ 177720000,
+ 264120000,
+ 350520000,
+ 436920000,
+ 523320000,
+ 609720000,
+ 696120000,
+ 782520000
+ ]
+ },
+ {
+ "schedule": "45 * * * *",
+ "triggerTimes": [
+ 2700000,
+ 6300000,
+ 9900000,
+ 13500000,
+ 17100000,
+ 20700000,
+ 24300000,
+ 27900000,
+ 31500000,
+ 35100000
+ ]
+ },
+ {
+ "schedule": "00 23 * * *",
+ "triggerTimes": [
+ 82800000,
+ 169200000,
+ 255600000,
+ 342000000,
+ 428400000,
+ 514800000,
+ 601200000,
+ 687600000,
+ 774000000,
+ 860400000
+ ]
+ },
+ {
+ "schedule": "3,6,9,12,18,21,24,27,33,36,39,42,48,51,54,57 * * * *",
+ "triggerTimes": [
+ 180000,
+ 360000,
+ 540000,
+ 720000,
+ 1080000,
+ 1260000,
+ 1440000,
+ 1620000,
+ 1980000,
+ 2160000
+ ]
+ },
+ {
+ "schedule": "32 1 * * *",
+ "triggerTimes": [
+ 5520000,
+ 91920000,
+ 178320000,
+ 264720000,
+ 351120000,
+ 437520000,
+ 523920000,
+ 610320000,
+ 696720000,
+ 783120000
+ ]
+ },
+ {
+ "schedule": "35 */2 * * *",
+ "triggerTimes": [
+ 2100000,
+ 9300000,
+ 16500000,
+ 23700000,
+ 30900000,
+ 38100000,
+ 45300000,
+ 52500000,
+ 59700000,
+ 66900000
+ ]
+ },
+ {
+ "schedule": "27 1 * * *",
+ "triggerTimes": [
+ 5220000,
+ 91620000,
+ 178020000,
+ 264420000,
+ 350820000,
+ 437220000,
+ 523620000,
+ 610020000,
+ 696420000,
+ 782820000
+ ]
+ },
+ {
+ "schedule": "0 21 * * 3",
+ "triggerTimes": [
+ 594000000,
+ 1198800000,
+ 1803600000,
+ 2408400000,
+ 3013200000,
+ 3618000000,
+ 4222800000,
+ 4827600000,
+ 5432400000,
+ 6037200000
+ ]
+ },
+ {
+ "schedule": "55 03 * * *",
+ "triggerTimes": [
+ 14100000,
+ 100500000,
+ 186900000,
+ 273300000,
+ 359700000,
+ 446100000,
+ 532500000,
+ 618900000,
+ 705300000,
+ 791700000
+ ]
+ },
+ {
+ "schedule": "0 23 2-31 * *",
+ "triggerTimes": [
+ 169200000,
+ 255600000,
+ 342000000,
+ 428400000,
+ 514800000,
+ 601200000,
+ 687600000,
+ 774000000,
+ 860400000,
+ 946800000
+ ]
+ },
+ {
+ "schedule": "09 11 * * *",
+ "triggerTimes": [
+ 40140000,
+ 126540000,
+ 212940000,
+ 299340000,
+ 385740000,
+ 472140000,
+ 558540000,
+ 644940000,
+ 731340000,
+ 817740000
+ ]
+ },
+ {
+ "schedule": "0 14 * * *",
+ "triggerTimes": [
+ 50400000,
+ 136800000,
+ 223200000,
+ 309600000,
+ 396000000,
+ 482400000,
+ 568800000,
+ 655200000,
+ 741600000,
+ 828000000
+ ]
+ },
+ {
+ "schedule": "20 2,12,22 * * *",
+ "triggerTimes": [
+ 8400000,
+ 44400000,
+ 80400000,
+ 94800000,
+ 130800000,
+ 166800000,
+ 181200000,
+ 217200000,
+ 253200000,
+ 267600000
+ ]
+ },
+ {
+ "schedule": "2,6,10,14,18,22,26,30,34,38,42,46,50,54,58 * * * *",
+ "triggerTimes": [
+ 120000,
+ 360000,
+ 600000,
+ 840000,
+ 1080000,
+ 1320000,
+ 1560000,
+ 1800000,
+ 2040000,
+ 2280000
+ ]
+ },
+ {
+ "schedule": "1 16,18,20 * * *",
+ "triggerTimes": [
+ 57660000,
+ 64860000,
+ 72060000,
+ 144060000,
+ 151260000,
+ 158460000,
+ 230460000,
+ 237660000,
+ 244860000,
+ 316860000
+ ]
+ },
+ {
+ "schedule": "30 */6 * * *",
+ "triggerTimes": [
+ 1800000,
+ 23400000,
+ 45000000,
+ 66600000,
+ 88200000,
+ 109800000,
+ 131400000,
+ 153000000,
+ 174600000,
+ 196200000
+ ]
+ },
+ {
+ "schedule": "00 06,15 * * *",
+ "triggerTimes": [
+ 21600000,
+ 54000000,
+ 108000000,
+ 140400000,
+ 194400000,
+ 226800000,
+ 280800000,
+ 313200000,
+ 367200000,
+ 399600000
+ ]
+ },
+ {
+ "schedule": "52 4,10,16,22 * * *",
+ "triggerTimes": [
+ 17520000,
+ 39120000,
+ 60720000,
+ 82320000,
+ 103920000,
+ 125520000,
+ 147120000,
+ 168720000,
+ 190320000,
+ 211920000
+ ]
+ },
+ {
+ "schedule": "37 1 * * *",
+ "triggerTimes": [
+ 5820000,
+ 92220000,
+ 178620000,
+ 265020000,
+ 351420000,
+ 437820000,
+ 524220000,
+ 610620000,
+ 697020000,
+ 783420000
+ ]
+ },
+ {
+ "schedule": "10 10,14 * * *",
+ "triggerTimes": [
+ 36600000,
+ 51000000,
+ 123000000,
+ 137400000,
+ 209400000,
+ 223800000,
+ 295800000,
+ 310200000,
+ 382200000,
+ 396600000
+ ]
+ },
+ {
+ "schedule": "2,7,12,17,22,27,32,37,42,47,52,57 * * * *",
+ "triggerTimes": [
+ 120000,
+ 420000,
+ 720000,
+ 1020000,
+ 1320000,
+ 1620000,
+ 1920000,
+ 2220000,
+ 2520000,
+ 2820000
+ ]
+ },
+ {
+ "schedule": "0 21 * * *",
+ "triggerTimes": [
+ 75600000,
+ 162000000,
+ 248400000,
+ 334800000,
+ 421200000,
+ 507600000,
+ 594000000,
+ 680400000,
+ 766800000,
+ 853200000
+ ]
+ },
+ {
+ "schedule": "25 * * * *",
+ "triggerTimes": [
+ 1500000,
+ 5100000,
+ 8700000,
+ 12300000,
+ 15900000,
+ 19500000,
+ 23100000,
+ 26700000,
+ 30300000,
+ 33900000
+ ]
+ },
+ {
+ "schedule": "0 15 * * *,,",
+ "triggerTimes": [
+ 54000000,
+ 140400000,
+ 226800000,
+ 313200000,
+ 399600000,
+ 486000000,
+ 572400000,
+ 658800000,
+ 745200000,
+ 831600000
+ ]
+ },
+ {
+ "schedule": "13 9,21 * * *",
+ "triggerTimes": [
+ 33180000,
+ 76380000,
+ 119580000,
+ 162780000,
+ 205980000,
+ 249180000,
+ 292380000,
+ 335580000,
+ 378780000,
+ 421980000
+ ]
+ },
+ {
+ "schedule": "10 * * * *",
+ "triggerTimes": [
+ 600000,
+ 4200000,
+ 7800000,
+ 11400000,
+ 15000000,
+ 18600000,
+ 22200000,
+ 25800000,
+ 29400000,
+ 33000000
+ ]
+ },
+ {
+ "schedule": "12 18 * * 1,3,5",
+ "triggerTimes": [
+ 151920000,
+ 411120000,
+ 583920000,
+ 756720000,
+ 1015920000,
+ 1188720000,
+ 1361520000,
+ 1620720000,
+ 1793520000,
+ 1966320000
+ ]
+ },
+ {
+ "schedule": "0 17-19 * * 1",
+ "triggerTimes": [
+ 406800000,
+ 410400000,
+ 414000000,
+ 1011600000,
+ 1015200000,
+ 1018800000,
+ 1616400000,
+ 1620000000,
+ 1623600000,
+ 2221200000
+ ]
+ },
+ {
+ "schedule": "0 10 * * *",
+ "triggerTimes": [
+ 36000000,
+ 122400000,
+ 208800000,
+ 295200000,
+ 381600000,
+ 468000000,
+ 554400000,
+ 640800000,
+ 727200000,
+ 813600000
+ ]
+ },
+ {
+ "schedule": "00 00 * * *",
+ "triggerTimes": [
+ 86400000,
+ 172800000,
+ 259200000,
+ 345600000,
+ 432000000,
+ 518400000,
+ 604800000,
+ 691200000,
+ 777600000,
+ 864000000
+ ]
+ },
+ {
+ "schedule": "25 16,17,18,22 * * *",
+ "triggerTimes": [
+ 59100000,
+ 62700000,
+ 66300000,
+ 80700000,
+ 145500000,
+ 149100000,
+ 152700000,
+ 167100000,
+ 231900000,
+ 235500000
+ ]
+ },
+ {
+ "schedule": "23 6,18 * * *",
+ "triggerTimes": [
+ 22980000,
+ 66180000,
+ 109380000,
+ 152580000,
+ 195780000,
+ 238980000,
+ 282180000,
+ 325380000,
+ 368580000,
+ 411780000
+ ]
+ },
+ {
+ "schedule": "17 1,9,17 * * 0",
+ "triggerTimes": [
+ 263820000,
+ 292620000,
+ 321420000,
+ 868620000,
+ 897420000,
+ 926220000,
+ 1473420000,
+ 1502220000,
+ 1531020000,
+ 2078220000
+ ]
+ },
+ {
+ "schedule": "00 16 * * *",
+ "triggerTimes": [
+ 57600000,
+ 144000000,
+ 230400000,
+ 316800000,
+ 403200000,
+ 489600000,
+ 576000000,
+ 662400000,
+ 748800000,
+ 835200000
+ ]
+ },
+ {
+ "schedule": "*/3 * * * *",
+ "triggerTimes": [
+ 180000,
+ 360000,
+ 540000,
+ 720000,
+ 900000,
+ 1080000,
+ 1260000,
+ 1440000,
+ 1620000,
+ 1800000
+ ]
+ },
+ {
+ "schedule": "19 * * * *",
+ "triggerTimes": [
+ 1140000,
+ 4740000,
+ 8340000,
+ 11940000,
+ 15540000,
+ 19140000,
+ 22740000,
+ 26340000,
+ 29940000,
+ 33540000
+ ]
+ },
+ {
+ "schedule": "15 * * * *",
+ "triggerTimes": [
+ 900000,
+ 4500000,
+ 8100000,
+ 11700000,
+ 15300000,
+ 18900000,
+ 22500000,
+ 26100000,
+ 29700000,
+ 33300000
+ ]
+ },
+ {
+ "schedule": "*/15 * * * *",
+ "triggerTimes": [
+ 900000,
+ 1800000,
+ 2700000,
+ 3600000,
+ 4500000,
+ 5400000,
+ 6300000,
+ 7200000,
+ 8100000,
+ 9000000
+ ]
+ },
+ {
+ "schedule": "0 22 * * 1",
+ "triggerTimes": [
+ 424800000,
+ 1029600000,
+ 1634400000,
+ 2239200000,
+ 2844000000,
+ 3448800000,
+ 4053600000,
+ 4658400000,
+ 5263200000,
+ 5868000000
+ ]
+ },
+ {
+ "schedule": "15 * * * *",
+ "triggerTimes": [
+ 900000,
+ 4500000,
+ 8100000,
+ 11700000,
+ 15300000,
+ 18900000,
+ 22500000,
+ 26100000,
+ 29700000,
+ 33300000
+ ]
+ },
+ {
+ "schedule": "20 04 * * *",
+ "triggerTimes": [
+ 15600000,
+ 102000000,
+ 188400000,
+ 274800000,
+ 361200000,
+ 447600000,
+ 534000000,
+ 620400000,
+ 706800000,
+ 793200000
+ ]
+ },
+ {
+ "schedule": "30 0,12 * * *",
+ "triggerTimes": [
+ 1800000,
+ 45000000,
+ 88200000,
+ 131400000,
+ 174600000,
+ 217800000,
+ 261000000,
+ 304200000,
+ 347400000,
+ 390600000
+ ]
+ },
+ {
+ "schedule": "15 */4 * * *",
+ "triggerTimes": [
+ 900000,
+ 15300000,
+ 29700000,
+ 44100000,
+ 58500000,
+ 72900000,
+ 87300000,
+ 101700000,
+ 116100000,
+ 130500000
+ ]
+ },
+ {
+ "schedule": "29 16,17,18,22 * * *",
+ "triggerTimes": [
+ 59340000,
+ 62940000,
+ 66540000,
+ 80940000,
+ 145740000,
+ 149340000,
+ 152940000,
+ 167340000,
+ 232140000,
+ 235740000
+ ]
+ },
+ {
+ "schedule": "37 */3 * * *",
+ "triggerTimes": [
+ 2220000,
+ 13020000,
+ 23820000,
+ 34620000,
+ 45420000,
+ 56220000,
+ 67020000,
+ 77820000,
+ 88620000,
+ 99420000
+ ]
+ },
+ {
+ "schedule": "*/15 * * * *",
+ "triggerTimes": [
+ 900000,
+ 1800000,
+ 2700000,
+ 3600000,
+ 4500000,
+ 5400000,
+ 6300000,
+ 7200000,
+ 8100000,
+ 9000000
+ ]
+ },
+ {
+ "schedule": "35 23 * * *",
+ "triggerTimes": [
+ 84900000,
+ 171300000,
+ 257700000,
+ 344100000,
+ 430500000,
+ 516900000,
+ 603300000,
+ 689700000,
+ 776100000,
+ 862500000
+ ]
+ },
+ {
+ "schedule": "0 17 * * *",
+ "triggerTimes": [
+ 61200000,
+ 147600000,
+ 234000000,
+ 320400000,
+ 406800000,
+ 493200000,
+ 579600000,
+ 666000000,
+ 752400000,
+ 838800000
+ ]
+ },
+ {
+ "schedule": "0 22 * * *",
+ "triggerTimes": [
+ 79200000,
+ 165600000,
+ 252000000,
+ 338400000,
+ 424800000,
+ 511200000,
+ 597600000,
+ 684000000,
+ 770400000,
+ 856800000
+ ]
+ },
+ {
+ "schedule": "0 11 * * *",
+ "triggerTimes": [
+ 39600000,
+ 126000000,
+ 212400000,
+ 298800000,
+ 385200000,
+ 471600000,
+ 558000000,
+ 644400000,
+ 730800000,
+ 817200000
+ ]
+ },
+ {
+ "schedule": "30 * * * *",
+ "triggerTimes": [
+ 1800000,
+ 5400000,
+ 9000000,
+ 12600000,
+ 16200000,
+ 19800000,
+ 23400000,
+ 27000000,
+ 30600000,
+ 34200000
+ ]
+ },
+ {
+ "schedule": "41 * * * *",
+ "triggerTimes": [
+ 2460000,
+ 6060000,
+ 9660000,
+ 13260000,
+ 16860000,
+ 20460000,
+ 24060000,
+ 27660000,
+ 31260000,
+ 34860000
+ ]
+ },
+ {
+ "schedule": "45 23 * * *",
+ "triggerTimes": [
+ 85500000,
+ 171900000,
+ 258300000,
+ 344700000,
+ 431100000,
+ 517500000,
+ 603900000,
+ 690300000,
+ 776700000,
+ 863100000
+ ]
+ },
+ {
+ "schedule": "*/2 * * * *",
+ "triggerTimes": [
+ 120000,
+ 240000,
+ 360000,
+ 480000,
+ 600000,
+ 720000,
+ 840000,
+ 960000,
+ 1080000,
+ 1200000
+ ]
+ },
+ {
+ "schedule": "0 0,3,6,9,12,15,18,21 * * *",
+ "triggerTimes": [
+ 10800000,
+ 21600000,
+ 32400000,
+ 43200000,
+ 54000000,
+ 64800000,
+ 75600000,
+ 86400000,
+ 97200000,
+ 108000000
+ ]
+ },
+ {
+ "schedule": "0,30 * * * *",
+ "triggerTimes": [
+ 1800000,
+ 3600000,
+ 5400000,
+ 7200000,
+ 9000000,
+ 10800000,
+ 12600000,
+ 14400000,
+ 16200000,
+ 18000000
+ ]
+ },
+ {
+ "schedule": "17 * * * *",
+ "triggerTimes": [
+ 1020000,
+ 4620000,
+ 8220000,
+ 11820000,
+ 15420000,
+ 19020000,
+ 22620000,
+ 26220000,
+ 29820000,
+ 33420000
+ ]
+ },
+ {
+ "schedule": "30,45 18 * * 1",
+ "triggerTimes": [
+ 412200000,
+ 413100000,
+ 1017000000,
+ 1017900000,
+ 1621800000,
+ 1622700000,
+ 2226600000,
+ 2227500000,
+ 2831400000,
+ 2832300000
+ ]
+ },
+ {
+ "schedule": "13,43 * * * *",
+ "triggerTimes": [
+ 780000,
+ 2580000,
+ 4380000,
+ 6180000,
+ 7980000,
+ 9780000,
+ 11580000,
+ 13380000,
+ 15180000,
+ 16980000
+ ]
+ },
+ {
+ "schedule": "0 0 10 * *",
+ "triggerTimes": [
+ 777600000,
+ 3456000000,
+ 5875200000,
+ 8553600000,
+ 11145600000,
+ 13824000000,
+ 16416000000,
+ 19094400000,
+ 21772800000,
+ 24364800000
+ ]
+ },
+ {
+ "schedule": "13,28,43,58 * * * *",
+ "triggerTimes": [
+ 780000,
+ 1680000,
+ 2580000,
+ 3480000,
+ 4380000,
+ 5280000,
+ 6180000,
+ 7080000,
+ 7980000,
+ 8880000
+ ]
+ },
+ {
+ "schedule": "17 9,13,22 * * *",
+ "triggerTimes": [
+ 33420000,
+ 47820000,
+ 80220000,
+ 119820000,
+ 134220000,
+ 166620000,
+ 206220000,
+ 220620000,
+ 253020000,
+ 292620000
+ ]
+ },
+ {
+ "schedule": "10 8,12 * * *",
+ "triggerTimes": [
+ 29400000,
+ 43800000,
+ 115800000,
+ 130200000,
+ 202200000,
+ 216600000,
+ 288600000,
+ 303000000,
+ 375000000,
+ 389400000
+ ]
+ },
+ {
+ "schedule": "*/5 * * * *",
+ "triggerTimes": [
+ 300000,
+ 600000,
+ 900000,
+ 1200000,
+ 1500000,
+ 1800000,
+ 2100000,
+ 2400000,
+ 2700000,
+ 3000000
+ ]
+ },
+ {
+ "schedule": "5,20,35,50 * * * *",
+ "triggerTimes": [
+ 300000,
+ 1200000,
+ 2100000,
+ 3000000,
+ 3900000,
+ 4800000,
+ 5700000,
+ 6600000,
+ 7500000,
+ 8400000
+ ]
+ },
+ {
+ "schedule": "00 */2 * * *",
+ "triggerTimes": [
+ 7200000,
+ 14400000,
+ 21600000,
+ 28800000,
+ 36000000,
+ 43200000,
+ 50400000,
+ 57600000,
+ 64800000,
+ 72000000
+ ]
+ },
+ {
+ "schedule": "23 * * * *",
+ "triggerTimes": [
+ 1380000,
+ 4980000,
+ 8580000,
+ 12180000,
+ 15780000,
+ 19380000,
+ 22980000,
+ 26580000,
+ 30180000,
+ 33780000
+ ]
+ },
+ {
+ "schedule": "7 12 * * *",
+ "triggerTimes": [
+ 43620000,
+ 130020000,
+ 216420000,
+ 302820000,
+ 389220000,
+ 475620000,
+ 562020000,
+ 648420000,
+ 734820000,
+ 821220000
+ ]
+ },
+ {
+ "schedule": "*/1 * * * *",
+ "triggerTimes": [
+ 60000,
+ 120000,
+ 180000,
+ 240000,
+ 300000,
+ 360000,
+ 420000,
+ 480000,
+ 540000,
+ 600000
+ ]
+ },
+ {
+ "schedule": "0,10,20,30,40,50 * * * *",
+ "triggerTimes": [
+ 600000,
+ 1200000,
+ 1800000,
+ 2400000,
+ 3000000,
+ 3600000,
+ 4200000,
+ 4800000,
+ 5400000,
+ 6000000
+ ]
+ },
+ {
+ "schedule": "45 02,06,10,14,18,22 * * *",
+ "triggerTimes": [
+ 9900000,
+ 24300000,
+ 38700000,
+ 53100000,
+ 67500000,
+ 81900000,
+ 96300000,
+ 110700000,
+ 125100000,
+ 139500000
+ ]
+ },
+ {
+ "schedule": "39 1 * * *",
+ "triggerTimes": [
+ 5940000,
+ 92340000,
+ 178740000,
+ 265140000,
+ 351540000,
+ 437940000,
+ 524340000,
+ 610740000,
+ 697140000,
+ 783540000
+ ]
+ },
+ {
+ "schedule": "0 0-2 * * 2-6",
+ "triggerTimes": [
+ 3600000,
+ 7200000,
+ 86400000,
+ 90000000,
+ 93600000,
+ 172800000,
+ 176400000,
+ 180000000,
+ 432000000,
+ 435600000
+ ]
+ },
+ {
+ "schedule": "35,50 * * * *",
+ "triggerTimes": [
+ 2100000,
+ 3000000,
+ 5700000,
+ 6600000,
+ 9300000,
+ 10200000,
+ 12900000,
+ 13800000,
+ 16500000,
+ 17400000
+ ]
+ },
+ {
+ "schedule": "0 3 1 * *",
+ "triggerTimes": [
+ 10800000,
+ 2689200000,
+ 5108400000,
+ 7786800000,
+ 10378800000,
+ 13057200000,
+ 15649200000,
+ 18327600000,
+ 21006000000,
+ 23598000000
+ ]
+ },
+ {
+ "schedule": "5 5 * * *",
+ "triggerTimes": [
+ 18300000,
+ 104700000,
+ 191100000,
+ 277500000,
+ 363900000,
+ 450300000,
+ 536700000,
+ 623100000,
+ 709500000,
+ 795900000
+ ]
+ },
+ {
+ "schedule": "18 8 * * *",
+ "triggerTimes": [
+ 29880000,
+ 116280000,
+ 202680000,
+ 289080000,
+ 375480000,
+ 461880000,
+ 548280000,
+ 634680000,
+ 721080000,
+ 807480000
+ ]
+ },
+ {
+ "schedule": "0 9 * * *",
+ "triggerTimes": [
+ 32400000,
+ 118800000,
+ 205200000,
+ 291600000,
+ 378000000,
+ 464400000,
+ 550800000,
+ 637200000,
+ 723600000,
+ 810000000
+ ]
+ },
+ {
+ "schedule": "*/1 * * * *",
+ "triggerTimes": [
+ 60000,
+ 120000,
+ 180000,
+ 240000,
+ 300000,
+ 360000,
+ 420000,
+ 480000,
+ 540000,
+ 600000
+ ]
+ },
+ {
+ "schedule": "50 8,12,21 * * *",
+ "triggerTimes": [
+ 31800000,
+ 46200000,
+ 78600000,
+ 118200000,
+ 132600000,
+ 165000000,
+ 204600000,
+ 219000000,
+ 251400000,
+ 291000000
+ ]
+ },
+ {
+ "schedule": "29 9,21 * * *",
+ "triggerTimes": [
+ 34140000,
+ 77340000,
+ 120540000,
+ 163740000,
+ 206940000,
+ 250140000,
+ 293340000,
+ 336540000,
+ 379740000,
+ 422940000
+ ]
+ },
+ {
+ "schedule": "40 * * * *",
+ "triggerTimes": [
+ 2400000,
+ 6000000,
+ 9600000,
+ 13200000,
+ 16800000,
+ 20400000,
+ 24000000,
+ 27600000,
+ 31200000,
+ 34800000
+ ]
+ },
+ {
+ "schedule": "8 21 * * *",
+ "triggerTimes": [
+ 76080000,
+ 162480000,
+ 248880000,
+ 335280000,
+ 421680000,
+ 508080000,
+ 594480000,
+ 680880000,
+ 767280000,
+ 853680000
+ ]
+ },
+ {
+ "schedule": "0 6 * * *",
+ "triggerTimes": [
+ 21600000,
+ 108000000,
+ 194400000,
+ 280800000,
+ 367200000,
+ 453600000,
+ 540000000,
+ 626400000,
+ 712800000,
+ 799200000
+ ]
+ },
+ {
+ "schedule": "30 0-23/2 * * *",
+ "triggerTimes": [
+ 1800000,
+ 9000000,
+ 16200000,
+ 23400000,
+ 30600000,
+ 37800000,
+ 45000000,
+ 52200000,
+ 59400000,
+ 66600000
+ ]
+ },
+ {
+ "schedule": "0 14,22 * * *",
+ "triggerTimes": [
+ 50400000,
+ 79200000,
+ 136800000,
+ 165600000,
+ 223200000,
+ 252000000,
+ 309600000,
+ 338400000,
+ 396000000,
+ 424800000
+ ]
+ },
+ {
+ "schedule": "0 */1 * * *",
+ "triggerTimes": [
+ 3600000,
+ 7200000,
+ 10800000,
+ 14400000,
+ 18000000,
+ 21600000,
+ 25200000,
+ 28800000,
+ 32400000,
+ 36000000
+ ]
+ },
+ {
+ "schedule": "0 1 * * 1",
+ "triggerTimes": [
+ 349200000,
+ 954000000,
+ 1558800000,
+ 2163600000,
+ 2768400000,
+ 3373200000,
+ 3978000000,
+ 4582800000,
+ 5187600000,
+ 5792400000
+ ]
+ },
+ {
+ "schedule": "0 8 * * *",
+ "triggerTimes": [
+ 28800000,
+ 115200000,
+ 201600000,
+ 288000000,
+ 374400000,
+ 460800000,
+ 547200000,
+ 633600000,
+ 720000000,
+ 806400000
+ ]
+ },
+ {
+ "schedule": "01 17 * * *",
+ "triggerTimes": [
+ 61260000,
+ 147660000,
+ 234060000,
+ 320460000,
+ 406860000,
+ 493260000,
+ 579660000,
+ 666060000,
+ 752460000,
+ 838860000
+ ]
+ },
+ {
+ "schedule": "13 * * * *",
+ "triggerTimes": [
+ 780000,
+ 4380000,
+ 7980000,
+ 11580000,
+ 15180000,
+ 18780000,
+ 22380000,
+ 25980000,
+ 29580000,
+ 33180000
+ ]
+ }
+]
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java b/src/test/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java
deleted file mode 100644
index 0ff8d12..0000000
--- a/src/test/java/org/apache/aurora/scheduler/cron/CrontabEntryTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron;
-
-import java.util.List;
-import java.util.Set;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-public class CrontabEntryTest {
- @Test
- public void testHashCodeAndEquals() {
- List<CrontabEntry> entries = ImmutableList.of(
- CrontabEntry.parse("* * * * *"),
- CrontabEntry.parse("0-59 * * * *"),
- CrontabEntry.parse("0-57,58,59 * * * *"),
- CrontabEntry.parse("* 23,1,2,4,0-22 * * *"),
- CrontabEntry.parse("1-50,0,51-59 * * * sun-sat"));
-
- for (CrontabEntry lhs : entries) {
- for (CrontabEntry rhs : entries) {
- assertEquals(lhs, rhs);
- }
- }
-
- Set<CrontabEntry> equivalentEntries = Sets.newHashSet(entries);
- assertTrue(equivalentEntries.size() == 1);
- }
-
- @Test
- public void testEqualsCoverage() {
- assertNotEquals(CrontabEntry.parse("* * * * *"), new Object());
-
- assertNotEquals(CrontabEntry.parse("* * * * *"), CrontabEntry.parse("1 * * * *"));
- assertEquals(CrontabEntry.parse("1,2,3 * * * *"), CrontabEntry.parse("1-3 * * * *"));
-
- assertNotEquals(CrontabEntry.parse("* 0-22 * * *"), CrontabEntry.parse("* * * * *"));
- assertEquals(CrontabEntry.parse("* 0-23 * * *"), CrontabEntry.parse("* * * * *"));
-
- assertNotEquals(CrontabEntry.parse("1 1 1-30 * *"), CrontabEntry.parse("1 1 * * *"));
- assertEquals(CrontabEntry.parse("1 1 1-31 * *"), CrontabEntry.parse("1 1 * * *"));
-
- assertNotEquals(CrontabEntry.parse("1 1 * JAN,FEB-NOV *"), CrontabEntry.parse("1 1 * * *"));
- assertEquals(CrontabEntry.parse("1 1 * JAN,FEB-DEC *"), CrontabEntry.parse("1 1 * * *"));
-
- assertNotEquals(CrontabEntry.parse("* * * * SUN"), CrontabEntry.parse("* * * * SAT"));
- assertEquals(CrontabEntry.parse("* * * * 0"), CrontabEntry.parse("* * * * SUN"));
- }
-
- @Test
- public void testSkip() {
- assertEquals(CrontabEntry.parse("*/15 * * * *"), CrontabEntry.parse("0,15,30,45 * * * *"));
- assertEquals(
- CrontabEntry.parse("* */2 * * *"),
- CrontabEntry.parse("0-59 0,2,4,6,8,10,12-23/2 * * *"));
- }
-
- @Test
- public void testToString() {
- assertEquals("0-58 * * * *", CrontabEntry.parse("0,1-57,58 * * * *").toString());
- assertEquals("* * * * *", CrontabEntry.parse("* * * * *").toString());
- }
-
- @Test
- public void testWildcards() {
- CrontabEntry wildcardMinuteEntry = CrontabEntry.parse("* 1 1 1 *");
- assertEquals("*", wildcardMinuteEntry.getMinuteAsString());
- assertTrue(wildcardMinuteEntry.hasWildcardMinute());
- assertFalse(wildcardMinuteEntry.hasWildcardHour());
- assertFalse(wildcardMinuteEntry.hasWildcardDayOfMonth());
- assertFalse(wildcardMinuteEntry.hasWildcardMonth());
- assertTrue(wildcardMinuteEntry.hasWildcardDayOfWeek());
-
- CrontabEntry wildcardHourEntry = CrontabEntry.parse("1 * 1 1 *");
- assertEquals("*", wildcardHourEntry.getHourAsString());
- assertFalse(wildcardHourEntry.hasWildcardMinute());
- assertTrue(wildcardHourEntry.hasWildcardHour());
- assertFalse(wildcardHourEntry.hasWildcardDayOfMonth());
- assertFalse(wildcardHourEntry.hasWildcardMonth());
- assertTrue(wildcardHourEntry.hasWildcardDayOfWeek());
-
- CrontabEntry wildcardDayOfMonth = CrontabEntry.parse("1 1 * 1 *");
- assertEquals("*", wildcardDayOfMonth.getDayOfMonthAsString());
- assertFalse(wildcardDayOfMonth.hasWildcardMinute());
- assertFalse(wildcardDayOfMonth.hasWildcardHour());
- assertTrue(wildcardDayOfMonth.hasWildcardDayOfMonth());
- assertFalse(wildcardDayOfMonth.hasWildcardMonth());
- assertTrue(wildcardDayOfMonth.hasWildcardDayOfWeek());
-
- CrontabEntry wildcardMonth = CrontabEntry.parse("1 1 1 * *");
- assertEquals("*", wildcardMonth.getMonthAsString());
- assertFalse(wildcardMonth.hasWildcardMinute());
- assertFalse(wildcardMonth.hasWildcardHour());
- assertFalse(wildcardMonth.hasWildcardDayOfMonth());
- assertTrue(wildcardMonth.hasWildcardMonth());
- assertTrue(wildcardMonth.hasWildcardDayOfWeek());
-
- CrontabEntry wildcardDayOfWeek = CrontabEntry.parse("1 1 1 1 *");
- assertEquals("*", wildcardDayOfWeek.getDayOfWeekAsString());
- assertFalse(wildcardDayOfWeek.hasWildcardMinute());
- assertFalse(wildcardDayOfWeek.hasWildcardHour());
- assertFalse(wildcardDayOfWeek.hasWildcardDayOfMonth());
- assertFalse(wildcardDayOfWeek.hasWildcardMonth());
- assertTrue(wildcardDayOfWeek.hasWildcardDayOfWeek());
- }
-
- @Test
- public void testEqualsIsCanonical() {
- String rawEntry = "* * */3 * *";
- CrontabEntry input = CrontabEntry.parse(rawEntry);
- assertNotEquals(
- rawEntry + " is not the canonical form of " + input,
- rawEntry,
- input.toString());
- assertEquals(
- "The form returned by toString is canonical",
- input.toString(),
- CrontabEntry.parse(input.toString()).toString());
- }
-
- @Test
- public void testBadEntries() {
- List<String> badPatterns = ImmutableList.of(
- "* * * * MON-SUN",
- "* * **",
- "0-59 0-59 * * *",
- "1/1 * * * *",
- "5 5 * MAR-JAN *",
- "*/0 * * * *",
- "0-59/0 * * * *",
- "0-59/60 * * * *",
- "* * 1 * 1"
- );
-
- for (String pattern : badPatterns) {
- assertNull(CrontabEntry.tryParse(pattern).orNull());
- }
- }
-
- @Test
- public void testExpectedTriggerPredictionsParse() {
- for (ExpectedPrediction prediction : ExpectedPrediction.getAll()) {
- prediction.parseCrontabEntry();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/ExpectedPrediction.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/ExpectedPrediction.java b/src/test/java/org/apache/aurora/scheduler/cron/ExpectedPrediction.java
deleted file mode 100644
index 9040823..0000000
--- a/src/test/java/org/apache/aurora/scheduler/cron/ExpectedPrediction.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Copyright 2014 Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.aurora.scheduler.cron;
-
-import java.io.InputStreamReader;
-import java.util.List;
-
-import com.google.common.collect.ImmutableList;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-
-/**
- * A schedule and the expected iteratively-applied prediction results.
- */
-public final class ExpectedPrediction {
- private String schedule;
- private List<Long> triggerTimes;
-
- ExpectedPrediction() {
- // GSON constructor.
- }
-
- public static List<ExpectedPrediction> getAll() {
- return new Gson()
- .fromJson(
- new InputStreamReader(
- ExpectedPrediction.class.getResourceAsStream("expected-predictions.json")),
- new TypeToken<List<ExpectedPrediction>>() { }.getType());
- }
-
- public String getSchedule() {
- return schedule;
- }
-
- public List<Long> getTriggerTimes() {
- return ImmutableList.copyOf(triggerTimes);
- }
-
- public CrontabEntry parseCrontabEntry() {
- return CrontabEntry.parse(getSchedule());
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/5de2b1ab/src/test/java/org/apache/aurora/scheduler/cron/noop/NoopCronIT.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/noop/NoopCronIT.java b/src/test/java/org/apache/aurora/scheduler/cron/noop/NoopCronIT.java
new file mode 100644
index 0000000..a9b85d0
--- /dev/null
+++ b/src/test/java/org/apache/aurora/scheduler/cron/noop/NoopCronIT.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2013 Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.cron.noop;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+import org.apache.aurora.scheduler.cron.CronPredictor;
+import org.apache.aurora.scheduler.cron.CronScheduler;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class NoopCronIT {
+ private static final String SCHEDULE = "* * * * *";
+
+ private CronScheduler cronScheduler;
+ private CronPredictor cronPredictor;
+
+ @Before
+ public void setUp() {
+ Injector injector = Guice.createInjector(new NoopCronModule());
+ cronScheduler = injector.getInstance(CronScheduler.class);
+ cronPredictor = injector.getInstance(CronPredictor.class);
+ }
+
+ @Test
+ public void testLifecycle() throws Exception {
+ cronScheduler.startAsync().awaitRunning();
+ cronScheduler.stopAsync().awaitTerminated();
+ }
+
+ @Test
+ public void testSchedule() throws Exception {
+ cronScheduler.schedule(SCHEDULE, new Runnable() {
+ @Override
+ public void run() {
+ // No-op.
+ }
+ });
+
+ assertEquals(SCHEDULE, cronScheduler.getSchedule(SCHEDULE).orNull());
+
+ cronScheduler.deschedule(SCHEDULE);
+
+ assertNull(cronScheduler.getSchedule(SCHEDULE).orNull());
+ }
+}