Skip to content

Commit 23536a1

Browse files
authored
Merge pull request #21 from zhongwencool/document
docs: user ex_doc to generate document
2 parents 5f365e7 + 3fb76f4 commit 23536a1

File tree

8 files changed

+251
-152
lines changed

8 files changed

+251
-152
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@
175175

176176
END OF TERMS AND CONDITIONS
177177

178-
Copyright 2019, zhongwencool <zhongwencool@gmail.com>.
178+
Copyright 2019-2025, zhongwencool <zhongwencool@gmail.com>.
179179

180180
Licensed under the Apache License, Version 2.0 (the "License");
181181
you may not use this file except in compliance with the License.

README.md

Lines changed: 88 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,38 @@
1-
<!-- markdownlint-disable MD013 -->
2-
# ecron [![GitHub Actions][action-img]][action] [![codeCov-img]][codeCov] [![hex-img]][hex] [![tag]][tag] [![License]][License]
3-
[action]: https://github.com/zhongwencool/ecron
4-
[action-img]: https://github.com/zhongwencool/ecron/actions/workflows/ci.yml/badge.svg
5-
[codeCov]: https://codecov.io/gh/zhongwencool/ecron
6-
[codeCov-img]: https://codecov.io/gh/zhongwencool/ecron/branch/master/graph/badge.svg?token=FI9WAQ6UG5
7-
[hex]: https://hex.pm/packages/ecron
8-
[hex-img]: https://img.shields.io/hexpm/v/ecron.svg?style=flat
9-
[tag]: https://img.shields.io/github/tag/zhongwencool/ecron.svg
10-
[License]: https://img.shields.io/hexpm/l/ecron.svg
1+
# ecron [![GitHub Actions](https://github.com/zhongwencool/ecron/actions/workflows/ci.yml/badge.svg)](https://github.com/zhongwencool/ecron) [![CodeCov](https://codecov.io/gh/zhongwencool/ecron/branch/master/graph/badge.svg?token=FI9WAQ6UG5)](https://codecov.io/gh/zhongwencool/ecron) [![Hex](https://img.shields.io/hexpm/v/ecron.svg?style=flat)](https://hex.pm/packages/ecron) [![Tag](https://img.shields.io/github/tag/zhongwencool/ecron.svg)](https://img.shields.io/github/tag/zhongwencool/ecron.svg) [![License](https://img.shields.io/hexpm/l/ecron.svg)](https://img.shields.io/hexpm/l/ecron.svg) [![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/ecron/)
112

123
A lightweight and efficient cron-like job scheduling library for Erlang.
134

14-
## Overview
5+
# Overview
156
Ecron is designed to manage scheduled jobs within a single gen_server process, similar to the standard library's [stdlib's timer](http://erlang.org/doc/man/timer.html). It uses an ordered_set ETS table to organize jobs by the next run time, ensuring efficient execution. Unlike traditional cron, Ecoron does not poll the system every second, which reduces message overhead and process usage.
167

17-
more detail see [Implementation](#Implementation).
8+
## Key Features
189

19-
20-
### Key Features
2110
- Supports both cron-like and interval-based scheduling.
2211
- Well-tested with [PropTest](https://github.com/proper-testing/proper) [![codecov](https://codecov.io/gh/zhongwencool/ecron/branch/master/graph/badge.svg?token=FI9WAQ6UG5)](https://codecov.io/gh/zhongwencool/ecron).
2312
- Utilizes gen_server timeout mechanism for precise timing.
2413
- Efficient process management, avoiding high memory usage.
2514

26-
You can find a collection of general practices in [Full Erlang Examples](https://github.com/zhongwencool/ecron/blob/master/examples/titan_erlang) and [Full Elixir Examples](https://github.com/zhongwencool/ecron/blob/master/examples/titan_elixir).
27-
2815
## Installation
29-
30-
**Erlang**
31-
```erlang
16+
17+
<!-- tabs-open -->
18+
19+
### Erlang
20+
21+
```erlang
3222
%% rebar.config
3323
{deps, [ecron]}
34-
```
24+
```
25+
### Elixir
3526

36-
**Elixir**
37-
```elixir
27+
```elixir
3828
# mix.exs
3929
def deps do
4030
[{:ecron, "~> 1.0.1"}]
4131
end
4232
```
4333

34+
<!-- tabs-close -->
35+
4436
## Basic Usage
4537

4638
Configure Ecoron in your sys.config file with timezone and job specifications:
@@ -146,6 +138,9 @@ ok = ecron:delete(crontabuniqueName),
146138
EveryMFA = {io, format, ["Runs every 120 second.~n"]},
147139
{ok, _} = ecron:add(everyUniqueName, 120, EveryMFA),
148140
```
141+
142+
You can find a collection of general practices in [Full Erlang Examples](https://github.com/zhongwencool/ecron/blob/master/examples/titan_erlang) and [Full Elixir Examples](https://github.com/zhongwencool/ecron/blob/master/examples/titan_elixir).
143+
149144
## Debug Support
150145
151146
Ecron provides functions to assist with debugging:
@@ -225,97 +220,98 @@ Additionally, you can use `ecron:statistic(Name)` to see the job's latest 16 res
225220
|<-------|
226221
```
227222
228-
[Check this for global_jobs workflow](https://github.com/zhongwencool/ecron/blob/master/doc/global.md#Implementation).
223+
[Check this for global_jobs workflow](global.html#Implementation).
229224
230-
## Telemetry
225+
## CRON Expression Guide
231226
232-
Ecron publishes events through telemetry, allowing for monitoring and alerting,
233-
You can handle those events by [this guide](https://github.com/zhongwencool/ecron/blob/master/doc/telemetry.md).
227+
### Basic Format
234228
235-
## CRON Expression Format
229+
A cron expression consists of 5-6 fields representing time units:
236230
237-
A [cron expression](https://www.wikiwand.com/en/Cron) represents a set of times, using 5-6 space-separated fields.
238-
Currently, W (nearest weekday), L (last day of month/week), and # (nth weekday of the month) are not supported.
239-
240-
Most other features supported by popular cron implementations should work just fine.
241-
```shell script
242-
# ┌────────────── second (optional)
243-
# │ ┌──────────── minute
244-
# │ │ ┌────────── hour
245-
# │ │ │ ┌──────── day of month
246-
# │ │ │ │ ┌────── month
247-
# │ │ │ │ │ ┌──── day of week
248-
# │ │ │ │ │ │
249-
# │ │ │ │ │ │
250-
# 0 * * * * *
231+
```
232+
# ┌────────────── second (optional)
233+
# │ ┌──────────── minute
234+
# │ │ ┌────────── hour
235+
# │ │ │ ┌──────── day of month
236+
# │ │ │ │ ┌────── month
237+
# │ │ │ │ │ ┌──── day of week
238+
# │ │ │ │ │ │
239+
# │ │ │ │ │ │
240+
# 0 * * * * *
251241
```
252242
253-
Field name | Mandatory? | Allowed values | Allowed special characters
254-
---------- | ---------- | -------------- | --------------------------
255-
Seconds | No | 0-59 | * / , -
256-
Minutes | Yes | 0-59 | * / , -
257-
Hours | Yes | 0-23 | * / , -
258-
Day of month | Yes | 1-31 | * / , -
259-
Month | Yes | 1-12 or JAN-DEC | * / , -
260-
Day of week | Yes | 0-6 or SUN-SAT | * / , -
243+
### Field Values
261244
262-
Note: Month and Day-of-week field values are case-insensitive. "SUN", "Sun", and "sun" are equally accepted.
245+
Field | Required | Values | Special Characters
246+
Second | No | 0-59 | `* / , -`
247+
Minute | Yes | 0-59 | `* / , -`
248+
Hour | Yes | 0-23 | `* / , -`
249+
Day of Month | Yes | 1-31 | `* / , -`
250+
Month | Yes | 1-12 or JAN-DEC | `* / , -`
251+
Day of Week | Yes | 0-6 or SUN-SAT | `* / , -`
263252
264-
When specifying your cron values you'll need to make sure that your values fall within the ranges.
265-
For instance, some cron's use a 0-7 range for the day of week where both 0 and 7 represent Sunday. We do not.
253+
> **Note**: Month and Day-of-week values are case-insensitive.
266254
267255
### Special Characters
268-
#### Asterisk ( * )
269-
The asterisk indicates that the cron expression will match for all values of the field.
270-
For example, using an asterisk in the `month` field would indicate every month.
271256
272-
#### Slash ( / )
273-
Slashes are used to describe increments of ranges.
274-
For example, "3-59/15" in the `minutes` field would indicate the 3rd minute of the hour and every 15 minutes thereafter.
275-
The form "*/..." is equivalent to the form "First-Last/...", that is, an increment over the largest possible range of the field.
276-
The form "N/..." is accepted as meaning "N-Max/...", that is, starting at N, use the increment until the end of that specific range.
277-
It does not wrap around.
257+
- `*` - Any value
258+
- `/` - Step values (e.g., `*/15` - every 15 units)
259+
- `,` - Value list (e.g., `1,3,5`)
260+
- `-` - Range (e.g., `1-5`)
278261
279-
#### Comma ( , )
280-
Commas are used to separate items of a list.
281-
For example, using "MON,WED,FRI" in the `day_of_week` field would mean Mondays, Wednesdays and Fridays.
262+
### Predefined Schedules
282263
283-
#### Hyphen ( - )
284-
Hyphens are used to define ranges.
285-
For example, using "9-17" in the `hours`field would indicate every hour between 9am and 5pm inclusive.
264+
Expression | Description | Equivalent
265+
`@yearly` | Once a year (midnight, Jan 1) | `0 0 0 1 1 *`
266+
`@monthly` | Once a month (midnight, first day) | `0 0 0 1 * *`
267+
`@weekly` | Once a week (midnight, Sunday) | `0 0 0 * * 0`
268+
`@daily` | Once a day (midnight) | `0 0 0 * * *`
269+
`@hourly` | Once an hour | `0 0 * * * *`
270+
`@minutely` | Once a minute | `0 * * * * *`
286271
287-
## Predefined crontab
272+
### Fixed Intervals
288273
289-
You may use one of several pre-defined crontab in place of a cron expression.
274+
For simpler scheduling needs, use `@every` with a duration:
290275
291-
Entry | Description | Equivalent To
292-
----- | ----------- | -------------
293-
@yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 0 1 1 *
294-
@monthly | Run once a month, midnight, first of month | 0 0 0 1 * *
295-
@weekly | Run once a week, midnight between Sat/Sun | 0 0 0 * * 0
296-
@daily (or @midnight) | Run once a day, midnight | 0 0 0 * * *
297-
@hourly | Run once an hour, beginning of hour | 0 0 * * * *
298-
@minutely | Run once an minute, beginning of minute | 0 * * * * *
276+
```erlang
277+
% Run every 30 minutes
278+
"@every 30m"
299279
300-
>There are tools that help when constructing your cronjobs.
301-
>You might find something like [https://crontab.guru/](https://crontab.guru/) or [https://cronjob.xyz/](https://cronjob.xyz/) helpful.
302-
>But, note that these don't necessarily accept the exact same syntax as this library,
303-
>for instance, it doesn't accept the seconds field, so keep that in mind.
304-
>The best way to verify the spec format is `ecron:parse_spec("0 0 1 1 1-6 1", 10).`.
280+
% Run every 1 hour and 30 minutes
281+
"@every 1h30m"
282+
```
305283
306-
## Intervals
284+
Duration units: `d`(days), `h`(hours), `m`(minutes), `s`(seconds)
307285
308-
Ecron also supports scheduling jobs at fixed intervals:
286+
### Error Handling
309287
310-
```shell
311-
@every <duration>
312-
```
313-
For example, @every 1h30m10s schedules a job to run every 1 hour, 30 minutes, and 10 seconds.
288+
- Failed jobs don't affect other jobs
289+
- Execution results and timing are stored (last 16 runs)
290+
- Jobs can be configured as singleton or parallel
291+
- System time changes are handled gracefully
292+
293+
## Best Practices
294+
295+
1. **Job Names**
296+
- Use descriptive, unique names
297+
- Consider adding prefixes for different job types
298+
299+
2. **Time Windows**
300+
- Use start/end times for temporary jobs
301+
- Consider time zone implications
302+
303+
3. **Error Handling**
304+
- Implement proper error handling in job functions
305+
- Monitor job execution through telemetry
306+
307+
4. **Resource Management**
308+
- Group related jobs under same supervisor
309+
- Use `singleton: false` only when needed
310+
311+
5. **Testing**
312+
- Validate cron expressions before deployment
313+
- Test jobs with different time scenarios
314314
315-
>Note: The interval doesn't take the job runtime into account.
316-
>For example, if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
317-
>it only has 2 minutes of idle time between each run.
318-
319315
## Test
320316
321317
This command will run property-based tests, common tests, and generate a coverage report with verbose output.

changelog.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2+
### 1.0.2
3+
- Use ex_doc to update documentation.
4+
5+
### 1.0.1
6+
- Fix concurrent cron job execution timing issue.
7+
8+
### 1.0.0
9+
Nothing changed, just update version from 0.6.1 to 1.0.0.
10+
111
### 0.6.1
212
- fix some spec warning.
313
- upgrade telemetry to 1.1.0
File renamed without changes.

rebar.config

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
{profiles, [{test, [{deps, [proper]}]}]}.
77
{project_plugins, [
8-
rebar3_proper, covertool, {rebar3_edoc_extensions, "1.5.0"}, rebar3_format, erlfmt
8+
rebar3_proper, covertool, rebar3_ex_doc, rebar3_format, erlfmt
99
]}.
1010

1111
{cover_enabled, true}.
@@ -24,15 +24,6 @@
2424
deprecated_functions
2525
]}.
2626

27-
{edoc_opts, [
28-
{stylesheet, "stylesheet.css"},
29-
{preprocess, true},
30-
{includes, ["."]},
31-
{sort_functions, false},
32-
{doclet, edoc_doclet_chunks},
33-
{layout, edoc_layout_chunks}
34-
]}.
35-
3627
{alias, [
3728
{check, [
3829
xref,
@@ -55,3 +46,23 @@
5546
%% ...or no options at all.
5647
{options, #{print_width => 120, ignore_pragma => true}}
5748
]}.
49+
50+
{hex, [
51+
{doc, #{provider => ex_doc}}
52+
]}.
53+
54+
{ex_doc, [
55+
{extras, [
56+
{"README.md", #{title => "Overview"}},
57+
58+
{"telemetry.md", #{title => "Telemetry"}},
59+
{"global.md", #{title => "Cluster Task"}},
60+
{"CHANGELOG.md", #{title => "Changelog"}},
61+
{"LICENSE", #{title => "License"}}
62+
]},
63+
{main, "README.md"},
64+
{homepage_url, "https://github.com/zhongwencool/ecron"},
65+
{source_url, "https://github.com/zhongwencool/ecron"},
66+
{api_reference, false},
67+
{with_mermaid, true}
68+
]}.

src/ecron.app.src

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{application, ecron, [
22
{description, "cron-like/crontab job scheduling library"},
3-
{vsn, "1.0.1"},
3+
{vsn, "1.0.2"},
44
{registered, [ecron_sup, ecron_local, ecron_monitor]},
55
{mod, {ecron_app, []}},
66
{applications, [kernel, stdlib, telemetry]},
@@ -31,6 +31,6 @@
3131
]}
3232
]},
3333
{modules, []},
34-
{licenses, ["Apache 2.0"]},
34+
{licenses, ["Apache-2.0"]},
3535
{links, [{"Github", "https://github.com/zhongwencool/ecron"}]}
3636
]}.

0 commit comments

Comments
 (0)