@@ -20,22 +20,27 @@ namespace client {
2020DirectoryRegistrationKeepAlive::DirectoryRegistrationKeepAlive (
2121 DirectoryRegistrationClient* directory_registration_client,
2222 const ::bosdyn::api::ServiceEntry& service_entry, const ::bosdyn::api::Endpoint& endpoint,
23- ::bosdyn::common::Duration rpc_interval, FaultClient* fault_client)
23+ ::bosdyn::common::Duration rpc_interval, FaultClient* fault_client,
24+ std::function<ErrorCallbackResult(const ::bosdyn::common::Status&)> error_callback,
25+ ::bosdyn::common::Duration registration_initial_retry_interval)
2426 : m_directory_registration_client(directory_registration_client),
2527 m_service_entry (service_entry),
2628 m_endpoint(endpoint),
2729 m_registration_interval(rpc_interval),
30+ m_registration_initial_retry_interval(registration_initial_retry_interval),
2831 m_thread(),
32+ m_periodic_thread_helper(std::make_unique<PeriodicThreadHelper>()),
2933 m_thread_stopped(true ),
30- m_fault_client(fault_client) {}
34+ m_fault_client(fault_client),
35+ m_error_callback(error_callback) {}
36+
3137
3238DirectoryRegistrationKeepAlive::~DirectoryRegistrationKeepAlive () {
3339 Shutdown ();
3440 Unregister ().IgnoreError ();
3541}
3642
3743void DirectoryRegistrationKeepAlive::Start (const std::vector<std::string>& fault_attributes) {
38- m_should_exit = false ;
3944 m_thread_stopped = false ;
4045
4146 // Populate the registration fault with default values.
@@ -61,16 +66,20 @@ void DirectoryRegistrationKeepAlive::Start(const std::vector<std::string>& fault
6166bool DirectoryRegistrationKeepAlive::IsAlive () const { return !m_thread_stopped; }
6267
6368void DirectoryRegistrationKeepAlive::Shutdown () {
64- m_should_exit = true ;
65- m_thread.join ();
69+ m_periodic_thread_helper->Stop ();
70+ if (m_thread.joinable ()) {
71+ m_thread.join ();
72+ }
6673}
6774
6875UnregisterServiceResultType DirectoryRegistrationKeepAlive::Unregister () {
6976 return m_directory_registration_client->UnregisterService (m_service_entry.name ());
7077}
7178
7279void DirectoryRegistrationKeepAlive::PeriodicReregisterThreadMethod () {
73- bool first_time = true ;
80+
81+ ::bosdyn::common::Duration retry_interval = m_registration_initial_retry_interval;
82+ ::bosdyn::common::Duration wait_interval = m_registration_interval;
7483
7584 // Set up register and update requests
7685 ::bosdyn::api::RegisterServiceRequest register_service_request;
@@ -81,19 +90,15 @@ void DirectoryRegistrationKeepAlive::PeriodicReregisterThreadMethod() {
8190 update_service_request.mutable_service_entry ()->CopyFrom (m_service_entry);
8291
8392 // Continually attempt to register and update the service.
84- while (!m_should_exit) {
85- if (!first_time) {
86- std::this_thread::sleep_for (m_registration_interval);
87- }
88- first_time = false ;
89-
93+ do {
9094 // Register service.
9195 auto res_register =
9296 m_directory_registration_client->RegisterService (register_service_request);
9397 // Successful registration. Service faults are automatically cleared for the new service
9498 // by the directory registration service.
9599 if (res_register) {
96100 m_registration_fault_active = false ;
101+ wait_interval = m_registration_interval;
97102 continue ;
98103 }
99104 // If registration failed in a bad way.
@@ -102,6 +107,27 @@ void DirectoryRegistrationKeepAlive::PeriodicReregisterThreadMethod() {
102107 if (m_fault_client && m_fault_client->TriggerServiceFault (m_service_fault)) {
103108 m_registration_fault_active = true ;
104109 }
110+ auto action = ErrorCallbackResult::kResumeNormalOperation ;
111+ if (m_error_callback) {
112+ try {
113+ action = m_error_callback (res_register.status );
114+ } catch (const std::exception& e) {
115+ std::cerr << " Exception thrown in error callback: " << e.what () << std::endl;
116+ }
117+ }
118+ if (action == ErrorCallbackResult::kAbort ) {
119+ break ;
120+ }
121+ if (action == ErrorCallbackResult::kRetryImmediately ) {
122+ wait_interval = std::chrono::seconds (0 );
123+ } else if (action == ErrorCallbackResult::kRetryWithExponentialBackOff ) {
124+ // Exponentially increase the retry interval.
125+ wait_interval = retry_interval;
126+ retry_interval = std::min (retry_interval * 2 , m_registration_interval);
127+ } else {
128+ // Default action is to continue with the next iteration.
129+ wait_interval = m_registration_interval;
130+ }
105131 continue ;
106132 }
107133
@@ -112,6 +138,27 @@ void DirectoryRegistrationKeepAlive::PeriodicReregisterThreadMethod() {
112138 if (m_fault_client && m_fault_client->TriggerServiceFault (m_service_fault)) {
113139 m_registration_fault_active = true ;
114140 }
141+ auto action = ErrorCallbackResult::kResumeNormalOperation ;
142+ if (m_error_callback) {
143+ try {
144+ action = m_error_callback (res_register.status );
145+ } catch (const std::exception& e) {
146+ std::cerr << " Exception thrown in error callback: " << e.what () << std::endl;
147+ }
148+ }
149+ if (action == ErrorCallbackResult::kAbort ) {
150+ break ;
151+ }
152+ if (action == ErrorCallbackResult::kRetryImmediately ) {
153+ wait_interval = std::chrono::seconds (0 );
154+ } else if (action == ErrorCallbackResult::kRetryWithExponentialBackOff ) {
155+ // Exponentially increase the retry interval.
156+ wait_interval = retry_interval;
157+ retry_interval = std::min (retry_interval * 2 , m_registration_interval);
158+ } else {
159+ // Default action is to continue with the next iteration.
160+ wait_interval = m_registration_interval;
161+ }
115162 continue ;
116163 }
117164
@@ -121,9 +168,12 @@ void DirectoryRegistrationKeepAlive::PeriodicReregisterThreadMethod() {
121168 m_registration_fault_active = false ;
122169 }
123170 }
124- }
171+ wait_interval = m_registration_interval;
172+ retry_interval = m_registration_initial_retry_interval;
173+ } while (m_periodic_thread_helper->WaitForInterval (wait_interval));
125174
126175 m_thread_stopped = true ;
176+ m_periodic_thread_helper->Stop ();
127177}
128178
129179} // namespace client
0 commit comments