mirror of
				https://github.com/lightpanda-io/browser.git
				synced 2025-10-29 15:13:28 +00:00 
			
		
		
		
	Ability to run tasks even in the "distant" future.
We previously ignored tasks scheduled more than 5 seconds away. These tasks are now scheduled on the low priority queue. This means that they won't stop a page.wait for returning, but they'll still [eventually] be run if page.wait is called multiple times. Practically, this means that they'll never be run in `fetch` mode, but they might be run from CDP if the driver waits. Make queue names consistent, primary => high_priority, secondary => low_priority (the same names used by the page)
This commit is contained in:
		| @@ -22,24 +22,24 @@ const Allocator = std.mem.Allocator; | ||||
|  | ||||
| const Scheduler = @This(); | ||||
|  | ||||
| primary: Queue, | ||||
| high_priority: Queue, | ||||
|  | ||||
| // For repeating tasks. We only want to run these if there are other things to | ||||
| // do. We don't, for example, want a window.setInterval or the page.runMicrotasks | ||||
| // to block the page.wait. | ||||
| secondary: Queue, | ||||
| low_priority: Queue, | ||||
|  | ||||
| // we expect allocator to be the page arena, hence we never call primary.deinit | ||||
| // we expect allocator to be the page arena, hence we never call high_priority.deinit | ||||
| pub fn init(allocator: Allocator) Scheduler { | ||||
|     return .{ | ||||
|         .primary = Queue.init(allocator, {}), | ||||
|         .secondary = Queue.init(allocator, {}), | ||||
|         .high_priority = Queue.init(allocator, {}), | ||||
|         .low_priority = Queue.init(allocator, {}), | ||||
|     }; | ||||
| } | ||||
|  | ||||
| pub fn reset(self: *Scheduler) void { | ||||
|     self.primary.clearRetainingCapacity(); | ||||
|     self.secondary.clearRetainingCapacity(); | ||||
|     self.high_priority.clearRetainingCapacity(); | ||||
|     self.low_priority.clearRetainingCapacity(); | ||||
| } | ||||
|  | ||||
| const AddOpts = struct { | ||||
| @@ -47,13 +47,16 @@ const AddOpts = struct { | ||||
|     low_priority: bool = false, | ||||
| }; | ||||
| pub fn add(self: *Scheduler, ctx: *anyopaque, func: Task.Func, ms: u32, opts: AddOpts) !void { | ||||
|     var low_priority = opts.low_priority; | ||||
|     if (ms > 5_000) { | ||||
|         log.warn(.user_script, "long timeout ignored", .{ .delay = ms }); | ||||
|         // ignore any task that we're almost certainly never going to run | ||||
|         return; | ||||
|         // we don't want tasks in the far future to block page.wait from | ||||
|         // completing. However, if page.wait is called multiple times (maybe | ||||
|         // a CDP driver is wait for something to happen), then we do want | ||||
|         // to [eventually] run these when their time is up. | ||||
|         low_priority = true; | ||||
|     } | ||||
|  | ||||
|     var q = if (opts.low_priority) &self.secondary else &self.primary; | ||||
|     var q = if (low_priority) &self.low_priority else &self.high_priority; | ||||
|     return q.add(.{ | ||||
|         .ms = std.time.milliTimestamp() + ms, | ||||
|         .ctx = ctx, | ||||
| @@ -63,11 +66,11 @@ pub fn add(self: *Scheduler, ctx: *anyopaque, func: Task.Func, ms: u32, opts: Ad | ||||
| } | ||||
|  | ||||
| pub fn runHighPriority(self: *Scheduler) !?i32 { | ||||
|     return self.runQueue(&self.primary); | ||||
|     return self.runQueue(&self.high_priority); | ||||
| } | ||||
|  | ||||
| pub fn runLowPriority(self: *Scheduler) !?i32 { | ||||
|     return self.runQueue(&self.secondary); | ||||
|     return self.runQueue(&self.low_priority); | ||||
| } | ||||
|  | ||||
| fn runQueue(self: *Scheduler, queue: *Queue) !?i32 { | ||||
| @@ -94,7 +97,7 @@ fn runQueue(self: *Scheduler, queue: *Queue) !?i32 { | ||||
|  | ||||
|             var copy = task; | ||||
|             copy.ms = now + repeat_delay; | ||||
|             try self.secondary.add(copy); | ||||
|             try self.low_priority.add(copy); | ||||
|         } | ||||
|         _ = queue.remove(); | ||||
|         next = queue.peek(); | ||||
| @@ -144,11 +147,11 @@ test "Scheduler" { | ||||
|     try testing.expectEqualSlices(u32, &.{ 1, 1, 2 }, task.calls.items); | ||||
|  | ||||
|     std.Thread.sleep(std.time.ns_per_ms * 5); | ||||
|     // wont' run secondary | ||||
|     // won't run low_priority | ||||
|     try testing.expectEqual(null, try s.runHighPriority()); | ||||
|     try testing.expectEqualSlices(u32, &.{ 1, 1, 2 }, task.calls.items); | ||||
|  | ||||
|     //runs secondary | ||||
|     //runs low_priority | ||||
|     try testing.expectDelta(2, try s.runLowPriority(), 1); | ||||
|     try testing.expectEqualSlices(u32, &.{ 1, 1, 2, 2 }, task.calls.items); | ||||
| } | ||||
|   | ||||
| @@ -277,16 +277,6 @@ pub const Window = struct { | ||||
|     }; | ||||
|     fn createTimeout(self: *Window, cbk: Function, delay_: ?u32, page: *Page, opts: CreateTimeoutOpts) !u32 { | ||||
|         const delay = delay_ orelse 0; | ||||
|         if (delay > 5000) { | ||||
|             if (!@import("builtin").is_test) { | ||||
|                 log.warn(.user_script, "long timeout ignored", .{ .delay = delay, .interval = opts.repeat }); | ||||
|             } | ||||
|             // self.timer_id is u30, so the largest value we can generate is | ||||
|             // 1_073_741_824. Returning 2_000_000_000 makes sure that clients | ||||
|             // can call cancelTimer/cancelInterval without breaking anything. | ||||
|             return 2_000_000_000; | ||||
|         } | ||||
|  | ||||
|         if (self.timers.count() > 512) { | ||||
|             return error.TooManyTimeout; | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Karl Seguin
					Karl Seguin