| // Copyright 2021 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:cocoon_service/src/service/datastore.dart'; |
| |
| import '../../model/appengine/task.dart'; |
| import '../logging.dart'; |
| import '../luci_build_service.dart'; |
| |
| /// Interface for implementing various scheduling policies in the Cocoon scheduler. |
| abstract class SchedulerPolicy { |
| /// Returns the priority of [Task]. |
| /// |
| /// If null is returned, the task should not be scheduled. |
| Future<int?> triggerPriority({ |
| required Task task, |
| required DatastoreService datastore, |
| }); |
| } |
| |
| /// Every [Task] is triggered to run. |
| class GuaranteedPolicy implements SchedulerPolicy { |
| @override |
| Future<int?> triggerPriority({ |
| required Task task, |
| required DatastoreService datastore, |
| }) async => |
| LuciBuildService.kDefaultPriority; |
| } |
| |
| /// [Task] is run at least every 3 commits. |
| /// |
| /// If there is capacity, a backfiller cron triggers the latest task that was not run |
| /// to ensure ToT is always tested. |
| /// |
| /// This is intended for targets that are run in an infra pool that has limited capacity, |
| /// such as the on device tests in the DeviceLab. |
| class BatchPolicy implements SchedulerPolicy { |
| static const int kBatchSize = 3; |
| @override |
| Future<int?> triggerPriority({ |
| required Task task, |
| required DatastoreService datastore, |
| }) async { |
| final List<Task> recentTasks = await datastore.queryRecentTasksByName(name: task.name!).toList(); |
| // Ensure task isn't considered in recentTasks |
| recentTasks.removeWhere((Task t) => t.commitKey == task.commitKey); |
| if (recentTasks.length < kBatchSize - 1) { |
| log.warning('${task.name} has less than $kBatchSize, triggerring all builds regardless of policy'); |
| return LuciBuildService.kDefaultPriority; |
| } |
| |
| // Prioritize tasks that recently failed. |
| if (_isFailed(recentTasks[0]) || _isFailed(recentTasks[1])) { |
| return LuciBuildService.kRerunPriority; |
| } |
| |
| if (recentTasks[0].status == Task.statusNew && recentTasks[1].status == Task.statusNew) { |
| return LuciBuildService.kDefaultPriority; |
| } |
| |
| return null; |
| } |
| |
| bool _isFailed(Task task) { |
| return task.status == Task.statusFailed || task.status == Task.statusInfraFailure; |
| } |
| } |
| |
| /// [Task] run outside of Cocoon are not triggered by the Cocoon scheduler. |
| class OmitPolicy implements SchedulerPolicy { |
| @override |
| Future<int?> triggerPriority({ |
| required Task task, |
| required DatastoreService datastore, |
| }) async => |
| null; |
| } |