@@ -17,6 +17,7 @@ type Expander struct {
1717 occurrenceRepo * repository.OccurrenceRepository
1818 lookAheadDuration time.Duration
1919 expansionInterval time.Duration
20+ gracePeriod time.Duration
2021 logger * zap.Logger
2122}
2223
@@ -27,6 +28,7 @@ func NewExpander(
2728 occurrenceRepo * repository.OccurrenceRepository ,
2829 lookAheadDuration time.Duration ,
2930 expansionInterval time.Duration ,
31+ gracePeriod time.Duration ,
3032 logger * zap.Logger ,
3133) * Expander {
3234 logger .Debug ("Initializing Expander" , zap .Duration ("lookAheadDuration" , lookAheadDuration ), zap .Duration ("expansionInterval" , expansionInterval ))
@@ -36,6 +38,7 @@ func NewExpander(
3638 occurrenceRepo : occurrenceRepo ,
3739 lookAheadDuration : lookAheadDuration ,
3840 expansionInterval : expansionInterval ,
41+ gracePeriod : gracePeriod ,
3942 logger : logger ,
4043 }
4144}
@@ -116,6 +119,7 @@ func (e *Expander) expandRecurringEvent(ctx context.Context, event *models.Event
116119
117120 // Get next occurrences based on schedule configuration
118121 now := time .Now ().UTC ()
122+ graceStart := now .Add (- e .gracePeriod )
119123 endTime := now .Add (e .lookAheadDuration )
120124 startTime := event .StartTime .UTC ()
121125
@@ -126,14 +130,14 @@ func (e *Expander) expandRecurringEvent(ctx context.Context, event *models.Event
126130 switch schedule .Frequency {
127131 case "daily" :
128132 for t := startTime ; t .Before (endTime ); t = t .AddDate (0 , 0 , schedule .Interval ) {
129- if t .After (now ) {
133+ if t .After (graceStart ) {
130134 occurrences = append (occurrences , t )
131135 }
132136 }
133137 case "weekly" :
134138 if len (schedule .ByDay ) == 0 {
135139 for t := startTime ; t .Before (endTime ); t = t .AddDate (0 , 0 , 7 * schedule .Interval ) {
136- if t .After (now ) {
140+ if t .After (graceStart ) {
137141 occurrences = append (occurrences , t )
138142 }
139143 }
@@ -152,7 +156,7 @@ func (e *Expander) expandRecurringEvent(ctx context.Context, event *models.Event
152156 weekday := weekdayMap [day ]
153157 daysToAdd := (int (weekday ) - int (t .Weekday ()) + 7 ) % 7
154158 nextDay := t .AddDate (0 , 0 , daysToAdd )
155- if nextDay .After (now ) && nextDay .Before (endTime ) {
159+ if nextDay .After (graceStart ) && nextDay .Before (endTime ) {
156160 occurrences = append (occurrences , nextDay )
157161 }
158162 }
@@ -161,15 +165,15 @@ func (e *Expander) expandRecurringEvent(ctx context.Context, event *models.Event
161165 case "monthly" :
162166 if len (schedule .ByMonthDay ) == 0 {
163167 for t := startTime ; t .Before (endTime ); t = t .AddDate (0 , schedule .Interval , 0 ) {
164- if t .After (now ) {
168+ if t .After (graceStart ) {
165169 occurrences = append (occurrences , t )
166170 }
167171 }
168172 } else {
169173 for t := startTime ; t .Before (endTime ); t = t .AddDate (0 , schedule .Interval , 0 ) {
170174 for _ , day := range schedule .ByMonthDay {
171175 nextDay := time .Date (t .Year (), t .Month (), day , t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ())
172- if nextDay .After (now ) && nextDay .Before (endTime ) {
176+ if nextDay .After (graceStart ) && nextDay .Before (endTime ) {
173177 occurrences = append (occurrences , nextDay )
174178 }
175179 }
@@ -178,15 +182,15 @@ func (e *Expander) expandRecurringEvent(ctx context.Context, event *models.Event
178182 case "yearly" :
179183 if len (schedule .ByMonth ) == 0 {
180184 for t := startTime ; t .Before (endTime ); t = t .AddDate (schedule .Interval , 0 , 0 ) {
181- if t .After (now ) {
185+ if t .After (graceStart ) {
182186 occurrences = append (occurrences , t )
183187 }
184188 }
185189 } else {
186190 for t := startTime ; t .Before (endTime ); t = t .AddDate (schedule .Interval , 0 , 0 ) {
187191 for _ , month := range schedule .ByMonth {
188192 nextMonth := time .Date (t .Year (), time .Month (month ), t .Day (), t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ())
189- if nextMonth .After (now ) && nextMonth .Before (endTime ) {
193+ if nextMonth .After (graceStart ) && nextMonth .Before (endTime ) {
190194 occurrences = append (occurrences , nextMonth )
191195 }
192196 }
@@ -239,13 +243,18 @@ func (e *Expander) expandNonRecurringEvent(ctx context.Context, event *models.Ev
239243 }
240244
241245 now := time .Now ().UTC ()
246+ graceStart := now .Add (- e .gracePeriod )
242247 startTime := event .StartTime .UTC ()
243248
244249 endTime := now .Add (e .lookAheadDuration )
245250 if startTime .After (endTime ) {
246251 e .logger .Info ("Event is beyond look-ahead window, skipping" , zap .String ("event_id" , event .ID .String ()))
247252 return nil
248253 }
254+ if startTime .Before (graceStart ) {
255+ e .logger .Info ("Event is before grace period, skipping" , zap .String ("event_id" , event .ID .String ()))
256+ return nil
257+ }
249258
250259 occurrence := & models.Occurrence {
251260 OccurrenceID : uuid .New (),
@@ -277,3 +286,19 @@ func (e *Expander) Run(ctx context.Context) error {
277286 }
278287 }
279288}
289+
290+ func (e * Expander ) ExpandRecurringEvent (ctx context.Context , event * models.Event ) error {
291+ return e .expandRecurringEvent (ctx , event )
292+ }
293+
294+ func (e * Expander ) ExpandNonRecurringEvent (ctx context.Context , event * models.Event ) error {
295+ return e .expandNonRecurringEvent (ctx , event )
296+ }
297+
298+ func (e * Expander ) GracePeriod () time.Duration {
299+ return e .gracePeriod
300+ }
301+
302+ func (e * Expander ) LookAheadDuration () time.Duration {
303+ return e .lookAheadDuration
304+ }
0 commit comments