Say when each job runs, what has to end first, and on which days
io.moderne.mainframe.controlm.AnalyzeControlMSchedulesio.moderne.recipe:recipes-mainframeUsage
Run this recipe
This recipe has no required configuration options. Users of Moderne can run it via the Moderne CLI.
You will need to have configured the Moderne CLI on your machine before you can run the following command.
mod run . --recipe AnalyzeControlMSchedules
If the recipe is not available locally, then you can install it using:
RELEASE resolves to the newest release and LATEST to the newest build of any kind, including snapshots. Either one lets mod config recipes upgrade pull in later versions without editing this command; a pinned version stays where you put it.
- RELEASE
- LATEST
- Pinned version
mod config recipes jar install io.moderne.recipe:recipes-mainframe:RELEASE
mod config recipes jar install io.moderne.recipe:recipes-mainframe:LATEST
mod config recipes jar install io.moderne.recipe:recipes-mainframe:0.1.0
Data tables
Control-M schedule
io.moderne.mainframe.analysis.table.ControlMScheduleEvery job the scheduler runs, with the JCL member it submits. A JCL member says what a job does and nothing anywhere else says when it runs, out of which library the member is taken, or under which table and application it is ordered — so this is the far end of the batch estate, and the row carries the definition as written for the Scheduler Info report.
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ControlMSchedule
| Column | Description |
|---|---|
| Job | The name the scheduler knows the job by. A table is a job too, and carries its own scheduling days and conditions. |
| Table | The table the job is ordered in, which is the folder it is written under in an export and the panel's GROUP field otherwise. A table names itself. |
| SMART table | Whether that table is a SMART table — one ordered, held and rerun as a unit, and so worth a containment edge — rather than a plain folder. Two folders of the same name, one of each kind, is a real export; nothing but this tells their jobs apart. A panel says which table a job is in but not what kind, so a job read from one always answers false, and so does a table itself. |
| Group | The group the definition names for itself: the panel's GROUP, the export's SUB_APPLICATION. The panel writes one field where the export writes two, so on a panel this is the table again. |
| Member name | The JCL member submitted, from MEMNAME. Empty for a table, which runs the jobs under it rather than a member of its own. |
| Member library | The library the member is taken from, from MEMLIB. Two applications routinely schedule a member of the same name out of different libraries. |
| Application | The application the job is ordered under. |
| Task type | Job for a member submitted to JES, SMART Table for a table, and a dozen others for the work the scheduler does itself. |
| Calendars | The calendars the scheduling days are validated against, each as the kind of decision it makes and the calendar name: CONFIRMATION says which days the job may run on at all, DAYS and WEEK which of the days written apply. |
| JCL path | The file the member was read from, empty where no member of that name was read. A schedule for a member nobody supplied is how a gap in an ingestion shows. |
| Definition path | The file the definition was written in: the export, or the member holding the one panel. |
| Definition line | The one-based line of that file the definition begins on. |
| Definition | The definition as written, which is what the Scheduler Info report shows. A table carries its jobs inside it, so a table's own definition is its opening tag. |
Control-M dependencies
io.moderne.mainframe.analysis.table.ControlMDependenciesWhich job the scheduler runs before which, one row per pair. Nothing in a schedule names another job: a job adds a condition when it ends and another job waits for that name, so the order the night runs in is only readable by joining the two — and the join holds across tables and across applications without either side saying so.
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ControlMDependencies
| Column | Description |
|---|---|
| Predecessor | The job that adds the condition, which is the one that has to end first. |
| Predecessor table | The table the predecessor is ordered in. |
| Predecessor path | The file the predecessor's definition was written in. |
| Predecessor line | The one-based line of that file the predecessor's definition begins on. |
| Successor | The job that waits for the condition. |
| Successor table | The table the successor is ordered in. |
| Successor path | The file the successor's definition was written in. |
| Successor line | The one-based line of that file the successor's definition begins on. |
| Condition | The name both jobs write and neither explains. Shops name it after the predecessor, which is convention rather than syntax — a chain whose names do not follow it still runs in this order. |
| Order date | The run the successor asks for the condition on: ODAT for today's, PREV for the one before, which is how a job waits on the work of the night before rather than on tonight's. |
| Across tables | Whether the two jobs are ordered in different tables. A chain inside one table is what an operator sees on one screen; one that leaves it is the dependency nobody remembers is there. |
Control-M calendars
io.moderne.mainframe.analysis.table.ControlMCalendarsThe days each calendar has, a row per year it carries. A schedule writes the days a job is a candidate to run on and the calendar decides which of those the shop is open for, so the days a job really runs are only readable by decoding the year as exported: twelve months of thirty-one positions, Y or N, a position past the end of a month being N.
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ControlMCalendars
| Column | Description |
|---|---|
| Calendar | The name the schedules refer to it by. |
| Type | Regular for a calendar of dates, Periodic for one whose days are named periods, Rule Based for one generated from a rule. |
| Data center | The Control-M data center the calendar is defined in. The same name is routinely defined in several, with different days in each. |
| Year | The year these days are in, or 0 for a calendar carrying no year — which is either a rule-based one or, where no file defines it at all, a gap in what was supplied. |
| Days | How many days of that year the calendar has. |
| Dates | Every day the calendar has, in order, as ISO dates. This is what turns "runs on CLMWORK" into the year calendar of execution days. |
| Definition path | The file the calendar was defined in, empty where a schedule names one no export defines. |
| Definition line | The one-based line of that file the definition begins on. |
Source files that had results
org.openrewrite.table.SourcesFileResultsSource files that were modified by the recipe run.
mod study . --last-recipe-run \
--data-table org.openrewrite.table.SourcesFileResults
| Column | Description |
|---|---|
| Source path before the run | The source path of the file before the run. null when a source file was created during the run. |
| Source path after the run | A recipe may modify the source path. This is the path after the run. null when a source file was deleted during the run. |
| Parent of the recipe that made changes | In a hierarchical recipe, the parent of the recipe that made a change. Empty if this is the root of a hierarchy or if the recipe is not hierarchical at all. |
| Recipe that made changes | The specific recipe that made a change. |
| Estimated time saving | An estimated effort that a developer to fix manually instead of using this recipe, in unit of seconds. |
| Cycle | The recipe cycle in which the change was made. |
Source files that had search results
org.openrewrite.table.SearchResultsSearch results that were found during the recipe run.
mod study . --last-recipe-run \
--data-table org.openrewrite.table.SearchResults
| Column | Description |
|---|---|
| Source path of search result before the run | The source path of the file with the search result markers present. |
| Source path of search result after run the run | A recipe may modify the source path. This is the path after the run. null when a source file was deleted during the run. |
| Result | The trimmed printed tree of the LST element that the marker is attached to. |
| Description | The content of the description of the marker. |
| Recipe that added the search marker | The specific recipe that added the Search marker. |
Source files that errored on a recipe
org.openrewrite.table.SourcesFileErrorsThe details of all errors produced by a recipe run.
mod study . --last-recipe-run \
--data-table org.openrewrite.table.SourcesFileErrors
| Column | Description |
|---|---|
| Source path | The file that failed to parse. |
| Recipe that made changes | The specific recipe that made a change. |
| Stack trace | The stack trace of the failure. |
Recipe performance
org.openrewrite.table.RecipeRunStatsStatistics used in analyzing the performance of recipes.
mod study . --last-recipe-run \
--data-table org.openrewrite.table.RecipeRunStats
| Column | Description |
|---|---|
| The recipe | The recipe whose stats are being measured both individually and cumulatively. |
| Source file count | The number of source files the recipe ran over. |
| Source file changed count | The number of source files which were changed in the recipe run. Includes files created, deleted, and edited. |
| Cumulative scanning time (ns) | The total time spent across the scanning phase of this recipe. |
| Max scanning time (ns) | The max time scanning any one source file. |
| Cumulative edit time (ns) | The total time spent across the editing phase of this recipe. |
| Max edit time (ns) | The max time editing any one source file. |