blob: 6cbe7ba055c7998e3e270ebff6a8b476c5bcad66 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
//! Live task views retain the exact page or task input; each update is a fresh authorized query.
use super::*;
impl Hub {
pub(super) async fn watch(
&self,
input: Value,
detail: bool,
context: &Context,
) -> Result<Value, String> {
let task: Option<contract::TaskRead> = if detail {
Some(serde_json::from_value(input.clone()).map_err(|_| "workhub_input_invalid")?)
} else {
None
};
let after = if detail {
None
} else {
serde_json::from_value::<contract::TasksRead>(input)
.map_err(|_| "workhub_input_invalid")?
.after
};
let stop = &context.scope().cancellation;
let mut commits = self.agent.0.store.subscribe_commits();
let mut previous = None;
loop {
if stop.is_cancelled() {
return Err("workhub_observation_cancelled".into());
}
let value = match &task {
Some(task) => {
self.task(&task.task_id, false, task.cursor.clone(), stop.clone())
.await?
}
None => self.task_list(after.clone()).await?,
};
if previous.as_ref() != Some(&value) {
context.emit(value.clone()).await?;
previous = Some(value);
}
tokio::select! {
() = stop.cancelled() => return Err("workhub_observation_cancelled".into()),
changed = commits.changed() => changed.map_err(|_| "workhub_observation_closed")?,
() = tokio::time::sleep(std::time::Duration::from_secs(2)) => {},
}
// Bound query fan-out while a worker streams. Remote workers without
// local commits are still observed by the same periodic read.
tokio::select! {
() = stop.cancelled() => return Err("workhub_observation_cancelled".into()),
() = tokio::time::sleep(std::time::Duration::from_millis(250)) => {},
}
commits.borrow_and_update();
}
}
}