|
15 | 15 | # limitations under the License. |
16 | 16 | # |
17 | 17 |
|
| 18 | +import enum |
18 | 19 | import math |
19 | 20 | import time |
20 | 21 | import warnings |
@@ -216,6 +217,21 @@ def expand(self, pcoll): |
216 | 217 | | 'MapToTimestamped' >> beam.Map(lambda tt: TimestampedValue(tt, tt))) |
217 | 218 |
|
218 | 219 |
|
| 220 | +class RebaseMode(enum.Enum): |
| 221 | + '''Controls how the start and stop timestamps are rebased to execution time. |
| 222 | +
|
| 223 | + Attributes: |
| 224 | + REBASE_NONE: Timestamps are not changed. |
| 225 | + REBASE_ALL: Both start and stop timestamps are rebased, preserving the |
| 226 | + original duration. |
| 227 | + REBASE_START: Only the start timestamp is rebased; the stop timestamp |
| 228 | + is unchanged. |
| 229 | + ''' |
| 230 | + REBASE_NONE = 0 |
| 231 | + REBASE_ALL = 1 |
| 232 | + REBASE_START = 2 |
| 233 | + |
| 234 | + |
219 | 235 | class PeriodicImpulse(PTransform): |
220 | 236 | ''' |
221 | 237 | PeriodicImpulse transform generates an infinite sequence of elements with |
@@ -270,7 +286,8 @@ def __init__( |
270 | 286 | stop_timestamp: TimestampTypes = MAX_TIMESTAMP, |
271 | 287 | fire_interval: float = 360.0, |
272 | 288 | apply_windowing: bool = False, |
273 | | - data: Optional[Sequence[Any]] = None): |
| 289 | + data: Optional[Sequence[Any]] = None, |
| 290 | + rebase: RebaseMode = RebaseMode.REBASE_NONE): |
274 | 291 | ''' |
275 | 292 | :param start_timestamp: Timestamp for first element. |
276 | 293 | :param stop_timestamp: Timestamp at or after which no elements will be |
@@ -301,21 +318,36 @@ def __init__( |
301 | 318 | sufficient to cover the duration defined by `start_timestamp`, |
302 | 319 | `stop_timestamp`, and `fire_interval`; otherwise, a `ValueError` is |
303 | 320 | raised. |
| 321 | +
|
| 322 | + :param rebase: Controls how the start and stop timestamps are rebased to |
| 323 | + execution time. See `RebaseMode` for more details. Defaults to |
| 324 | + `REBASE_NONE`. |
304 | 325 | ''' |
305 | 326 | self.start_ts = start_timestamp |
306 | 327 | self.stop_ts = stop_timestamp |
307 | 328 | self.interval = fire_interval |
308 | 329 | self.apply_windowing = apply_windowing |
309 | 330 | self.data = data |
| 331 | + self.rebase = rebase |
310 | 332 |
|
311 | 333 | if self.data: |
312 | 334 | self._validate_and_adjust_duration() |
313 | 335 |
|
314 | 336 | def expand(self, pbegin): |
| 337 | + if self.rebase == RebaseMode.REBASE_ALL: |
| 338 | + duration = Timestamp.of(self.stop_ts) - Timestamp.of(self.start_ts) |
| 339 | + impulse_element = pbegin | beam.Impulse() | beam.Map( |
| 340 | + lambda _: |
| 341 | + [Timestamp.now(), Timestamp.now() + duration, self.interval]) |
| 342 | + elif self.rebase == RebaseMode.REBASE_START: |
| 343 | + impulse_element = pbegin | beam.Impulse() | beam.Map( |
| 344 | + lambda _: [Timestamp.now(), self.stop_ts, self.interval]) |
| 345 | + else: |
| 346 | + impulse_element = pbegin | 'ImpulseElement' >> beam.Create( |
| 347 | + [(self.start_ts, self.stop_ts, self.interval)]) |
| 348 | + |
315 | 349 | result = ( |
316 | | - pbegin |
317 | | - | 'ImpulseElement' >> beam.Create( |
318 | | - [(self.start_ts, self.stop_ts, self.interval)]) |
| 350 | + impulse_element |
319 | 351 | | 'GenSequence' >> beam.ParDo(ImpulseSeqGenDoFn(self.data))) |
320 | 352 |
|
321 | 353 | if not self.data: |
|
0 commit comments