Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: add different time schedules #55

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,6 @@ settings.json

# Test results
test-results/

# Mac Preferences File
.DS_Store
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,29 @@ tsql_command = "SELECT TOP 10 * FROM sys.objects"

[[job.schedules]]
name = "name1"
every_n_minutes = 12
unit = "DAY"
every_n_units = 2
schedule_time = 200000

[[job.schedules]]
name = "name2"
every_n_minutes = 111
unit = "MINUTE"
every_n_units = 111

[[job.schedules]]
name = "name3"
unit = "WEEK"
every_n_units = 1
run_days = [
"MONDAY",
"TUESDAY"
]

[[job.schedules]]
name = "name4"
unit = "MONTH"
every_n_units = 3
day_of_month = 12
```

Note, when configuring a T-SQL step in an agent job, the default database
Expand All @@ -145,3 +163,16 @@ sql-deployment-tools deploy --replacement-tokens '{"SECRET_VALUE": "***"}'
```text
Driver={SQL Server Native Client 11.0};Server=.;Database=SSISDB;Trusted_Connection=yes;
```

### Schedules TOML keys

| key | type | required | allowable values | description |
|-----|------|----------|------------------|-------------|
| name | str | yes | any string | schedule name |
| unit | str | yes | "MINUTE" "DAY" "WEEK" "MONTH" | time unit |
| every\_n\_units | int | yes | any integer | x value in: repeats every _x unit_s |
| schedule\_time | int | no _default:0_ | integer time value HHMMSS in 24h clock e.g 0 is midnight, 70000 is 7am, 190000 is 7pm | job scheduled start time in 24h clock |
| run\_days | List[str] | when unit = "WEEK" | str values: "SUNDAY" "MONDAY" "TUESDAY" "WEDNESDAY" "THURSDAY" "FRIDAY" "SATURDAY" | days of the week that job should run |
| day\_of\_month | int | when unit = "MONTH" | any integer | day of the month to run scheduled job. 1 being first day of month |
| window_start | int _default:0_| optional when unit = "MINUTE", ignored otherwise | integer time value HHMMSS in 24h clock e.g 0 is midnight, 70000 is 7am, 190000 is 7pm | start time of window in which to run job |
| window_end | int _default:235959_| optional when unit = "MINUTE", ignored otherwise | integer time value HHMMSS in 24h clock e.g 0 is midnight, 70000 is 7am, 190000 is 7pm | end time of window in which to run job |
12 changes: 9 additions & 3 deletions src/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,17 @@ def deploy_ssis(
)

for job_schedule in ssis_deployment.job.schedules:
db.agent_create_job_schedule_occurs_every_n_minutes(
parameters = job_schedule.transform_for_query()
db.agent_create_job_schedule(
job_name,
job_schedule.name,
job_schedule.every_n_minutes,
job_schedule.start_time,
parameters.freq_type,
parameters.freq_interval,
parameters.freq_subday_type,
parameters.freq_subday_interval,
parameters.freq_recurrence_factor,
parameters.active_start_time,
parameters.active_end_time,
)

if ssis_deployment.job.notification_email_address:
Expand Down
89 changes: 83 additions & 6 deletions src/model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import datetime
import typing
from dataclasses import dataclass, field
from enum import Enum
Expand Down Expand Up @@ -28,22 +27,100 @@ class NotifyLevelEmail(Enum):
ALWAYS = 3


class UnitTypeFrequencyType(Enum):
MINUTE = 4
DAY = 4
WEEK = 8
MONTH = 16


class DayOfWeekFrequencyInterval(Enum):
SUNDAY = 1
MONDAY = 2
TUESDAY = 4
WEDNESDAY = 8
THURSDAY = 16
FRIDAY = 32
SATURDAY = 64


@dataclass
class Parameter:
name: str
value: str
sensitive: bool = False


@dataclass
class ScheduleQueryParameters:
freq_type: int
freq_interval: int
freq_subday_type: int
freq_subday_interval: int
freq_recurrence_factor: int
active_start_time: int
active_end_time: int


@dataclass_json
@dataclass
class Schedule:
name: str
every_n_minutes: int
start_time: datetime.time = field(
default=datetime.time(hour=0, minute=0, second=0),
metadata=config(decoder=datetime.time.fromisoformat),
)
unit: str
every_n_units: int
schedule_time: int = 0
window_start: int = 0
window_end: int = 235959
run_days: typing.Optional[typing.List[str]] = None
day_of_month: typing.Optional[int] = None

def transform_for_query(self) -> ScheduleQueryParameters:
if self.unit == "MINUTE":
return ScheduleQueryParameters(
UnitTypeFrequencyType.MINUTE.value,
1,
4,
self.every_n_units,
0,
self.window_start,
self.window_end,
)
if self.unit == "DAY":
return ScheduleQueryParameters(
UnitTypeFrequencyType.DAY.value,
self.every_n_units,
1,
0,
0,
self.schedule_time,
235959,
)
if self.unit == "WEEK":
return ScheduleQueryParameters(
UnitTypeFrequencyType.WEEK.value,
sum([DayOfWeekFrequencyInterval[x].value for x in self.run_days]),
1,
0,
self.every_n_units,
self.schedule_time,
235959,
)
if self.unit == "MONTH":
return ScheduleQueryParameters(
UnitTypeFrequencyType.MONTH.value,
self.day_of_month,
1,
0,
self.every_n_units,
self.schedule_time,
235959,
)

def __post_init__(self):
if self.unit == "WEEK" and not self.run_days:
raise ConfigurationError("'run_days must be provided.'")
elif self.unit == "MONTH" and not self.day_of_month:
raise ConfigurationError("'day_of_month must be provided.'")


@dataclass
Expand Down
13 changes: 7 additions & 6 deletions src/sql/agent/create_job_schedule.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ EXEC msdb.dbo.sp_add_jobschedule
@job_name = $job_name
, @name = $schedule_name
, @enabled = 1 -- Enabled
, @freq_type = 4 -- Daily
, @freq_interval = 1 -- Once
, @freq_subday_type = 4 -- Every N Minutes
, @freq_subday_interval = $occurs_every_n_minutes
, @freq_type = $freq_type
, @freq_interval = $freq_interval
, @freq_subday_type = $freq_subday_type
, @freq_subday_interval = $freq_subday_interval
, @freq_relative_interval = 0
, @freq_recurrence_factor = 1
, @active_start_time = $hh_mm_ss
, @freq_recurrence_factor = $freq_recurrence_factor
, @active_start_time = $active_start_time
, @active_end_time = $active_end_time
, @schedule_id = @schedule_id OUTPUT
;

Expand Down
21 changes: 15 additions & 6 deletions src/sql/db.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import datetime
import os

import pyodbc
Expand Down Expand Up @@ -235,20 +234,30 @@ def agent_create_job_step_tsql(

self._agent_reset_job_step_flow(job_name)

def agent_create_job_schedule_occurs_every_n_minutes(
def agent_create_job_schedule(
self,
job_name: str,
schedule_name: str,
every_n_minutes: int,
start_time: datetime.time,
freq_type: int,
freq_interval: int,
freq_subday_type: int,
freq_subday_interval: int,
freq_recurrence_factor: int,
active_start_time: int,
active_end_time: int,
):
self._execute_sql(
query.agent_create_job_schedule,
{
"job_name": job_name,
"schedule_name": schedule_name,
"occurs_every_n_minutes": every_n_minutes,
"hh_mm_ss": start_time.strftime("%H%M%S"),
"freq_type": freq_type,
"freq_interval": freq_interval,
"freq_subday_type": freq_subday_type,
"freq_subday_interval": freq_subday_interval,
"freq_recurrence_factor": freq_recurrence_factor,
"active_start_time": active_start_time,
"active_end_time": active_end_time,
},
)

Expand Down
27 changes: 25 additions & 2 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,31 @@
},
],
"schedules": [
{"name": "Winter Moon", "every_n_minutes": 30},
{"name": "Autumn Mountain", "every_n_minutes": 1440},
{
"name": "Winter Moon",
"unit": "DAY",
"every_n_units": 30,
"schedule_time": 200000,
},
{
"name": "Autumn Mountain",
"unit": "MINUTE",
"every_n_units": 1440,
"window_start": 100000,
"window_end": 120000,
},
{
"name": "Peaceful Valley",
"unit": "WEEK",
"every_n_units": 1,
"run_days": ["MONDAY", "FRIDAY"],
},
{
"name": "Snowfall",
"unit": "MONTH",
"every_n_units": 1,
"day_of_month": 15,
},
],
},
}
Empty file modified test/run_tests.sh
100644 → 100755
Empty file.
Loading