Index: chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc |
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc |
index d333cb94627dfad9331afc59102276e97efb1daa..9806dd7b78c3109ecbe98cdaf53ebae273759849 100644 |
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc |
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc |
@@ -33,6 +33,9 @@ namespace { |
// The rate in milliseconds at which we will poll CUPS for print job updates. |
const int kPollRate = 1000; |
+// Threshold for giving up on communicating with CUPS. |
+const int kRetryMax = 6; |
+ |
// Returns the equivalient CupsPrintJob#State from a CupsJob#JobState. |
chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) { |
using cpj = chromeos::CupsPrintJob::State; |
@@ -61,6 +64,13 @@ chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) { |
return cpj::STATE_NONE; |
} |
+chromeos::QueryResult QueryCups(::printing::CupsConnection* connection, |
+ const std::vector<std::string>& printer_ids) { |
+ chromeos::QueryResult result; |
+ result.success = connection->GetJobs(printer_ids, &result.queues); |
+ return result; |
+} |
+ |
} // namespace |
namespace chromeos { |
@@ -134,6 +144,7 @@ bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name, |
total_page_number); |
std::string key = cpj->GetUniqueId(); |
jobs_[key] = std::move(cpj); |
+ |
CupsPrintJob* job = jobs_[key].get(); |
NotifyJobCreated(job); |
@@ -153,36 +164,67 @@ void CupsPrintJobManagerImpl::ScheduleQuery() { |
void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) { |
if (!in_query_) { |
in_query_ = true; |
- content::BrowserThread::PostDelayedTask( |
- content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, |
- base::Bind(&CupsPrintJobManagerImpl::QueryCups, |
+ |
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&CupsPrintJobManagerImpl::PostQuery, |
weak_ptr_factory_.GetWeakPtr()), |
- base::TimeDelta::FromMilliseconds(kPollRate)); |
+ delay); |
} |
} |
-// Query CUPS asynchronously. Post results back to UI thread. |
-void CupsPrintJobManagerImpl::QueryCups() { |
- std::vector<::printing::CupsJob> jobs = cups_connection_.GetJobs(); |
+void CupsPrintJobManagerImpl::PostQuery() { |
+ // The set of active printers is expected to be small. |
+ std::set<std::string> printer_ids; |
+ for (const auto& entry : jobs_) { |
+ printer_ids.insert(entry.second->printer().id()); |
+ } |
+ std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()}; |
- content::BrowserThread::PostTask( |
- content::BrowserThread::ID::UI, FROM_HERE, |
+ content::BrowserThread::PostTaskAndReplyWithResult( |
+ content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, |
+ base::Bind(&QueryCups, &cups_connection_, ids), |
base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, |
- weak_ptr_factory_.GetWeakPtr(), jobs)); |
+ weak_ptr_factory_.GetWeakPtr())); |
} |
// Use job information to update local job states. Previously completed jobs |
// could be in |jobs| but those are ignored as we will not emit updates for them |
// after they are completed. |
-void CupsPrintJobManagerImpl::UpdateJobs( |
- const std::vector<::printing::CupsJob>& jobs) { |
+void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) { |
+ const std::vector<::printing::QueueStatus>& queues = result.queues; |
+ |
+ // Query has completed. Allow more queries. |
in_query_ = false; |
+ // If the query failed, either retry or purge. |
+ if (!result.success) { |
+ retry_count_++; |
+ LOG(WARNING) << "Failed to query CUPS for queue status. Schedule retry (" |
+ << retry_count_ << ")"; |
+ if (retry_count_ > kRetryMax) { |
+ LOG(ERROR) << "CUPS is unreachable. Giving up on all jobs."; |
+ PurgeJobs(); |
+ } else { |
+ // Schedule another query with a larger delay. |
+ DCHECK_GE(1, retry_count_); |
+ ScheduleQuery( |
+ base::TimeDelta::FromMilliseconds(kPollRate * retry_count_)); |
+ } |
+ return; |
+ } |
+ |
+ // A query has completed. Reset retry counter. |
+ retry_count_ = 0; |
+ |
std::vector<std::string> active_jobs; |
- for (auto& job : jobs) { |
- std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id); |
- const auto& entry = jobs_.find(key); |
- if (entry != jobs_.end()) { |
+ for (const auto& queue : queues) { |
+ for (auto& job : queue.jobs) { |
+ std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id); |
+ const auto& entry = jobs_.find(key); |
+ if (entry == jobs_.end()) |
+ continue; |
+ |
CupsPrintJob* print_job = entry->second.get(); |
// Update a job we're tracking. |
@@ -199,18 +241,23 @@ void CupsPrintJobManagerImpl::UpdateJobs( |
// Keep polling until all jobs complete or error. |
if (!active_jobs.empty()) { |
+ // During normal operations, we poll at the default rate. |
ScheduleQuery(); |
} else if (!jobs_.empty()) { |
// We're tracking jobs that we didn't receive an update for. Something bad |
// has happened. |
LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs"; |
- for (const auto& entry : jobs_) { |
- // Declare all lost jobs errors. |
- JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR); |
- } |
+ PurgeJobs(); |
+ } |
+} |
- jobs_.clear(); |
+void CupsPrintJobManagerImpl::PurgeJobs() { |
+ for (const auto& entry : jobs_) { |
+ // Declare all lost jobs errors. |
+ JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR); |
} |
+ |
+ jobs_.clear(); |
} |
void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job, |