1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 00:31:58 +00:00

[core] Deprecate set_retry, cancel_retry, and RetryResult

set_retry does a std::make_shared<RetryArgs>() heap allocation on every
invocation. No core component needs this pattern - all callers have been
migrated to set_timeout or set_interval in prior PRs. The feature wastes
flash and RAM on every firmware for a pattern that set_interval covers
better, and the hidden heap allocation is a footgun for component authors.

Deprecated in 2026.2.0, removal in 2026.8.0.

Depends on:
- #13841 [lps22] Replace set_retry with set_interval
- #13842 [ms8607] Replace set_retry with set_timeout chain
- #13843 [speaker] Replace set_retry with set_interval
- #13844 [esp32_hosted] Replace set_retry with set_interval
This commit is contained in:
J. Nick Koston
2026-02-07 14:26:13 -06:00
parent 9de91539e6
commit 2a6e20dd32
4 changed files with 66 additions and 54 deletions

View File

@@ -152,7 +152,10 @@ void Component::set_retry(const std::string &name, uint32_t initial_wait_time, u
void Component::set_retry(const char *name, uint32_t initial_wait_time, uint8_t max_attempts,
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor) { // NOLINT
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
App.scheduler.set_retry(this, name, initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
#pragma GCC diagnostic pop
}
bool Component::cancel_retry(const std::string &name) { // NOLINT
@@ -163,7 +166,10 @@ bool Component::cancel_retry(const std::string &name) { // NOLINT
}
bool Component::cancel_retry(const char *name) { // NOLINT
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return App.scheduler.cancel_retry(this, name);
#pragma GCC diagnostic pop
}
void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> &&f) { // NOLINT
@@ -203,10 +209,18 @@ bool Component::cancel_interval(uint32_t id) { return App.scheduler.cancel_inter
void Component::set_retry(uint32_t id, uint32_t initial_wait_time, uint8_t max_attempts,
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor) { // NOLINT
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
App.scheduler.set_retry(this, id, initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
#pragma GCC diagnostic pop
}
bool Component::cancel_retry(uint32_t id) { return App.scheduler.cancel_retry(this, id); }
bool Component::cancel_retry(uint32_t id) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return App.scheduler.cancel_retry(this, id);
#pragma GCC diagnostic pop
}
void Component::call_loop() { this->loop(); }
void Component::call_setup() { this->setup(); }
@@ -371,7 +385,10 @@ void Component::set_interval(uint32_t interval, std::function<void()> &&f) { //
}
void Component::set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std::function<RetryResult(uint8_t)> &&f,
float backoff_increase_factor) { // NOLINT
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
App.scheduler.set_retry(this, "", initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
#pragma GCC diagnostic pop
}
bool Component::is_failed() const { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; }
bool Component::is_ready() const {

View File

@@ -68,6 +68,7 @@ extern const uint8_t STATUS_LED_OK;
extern const uint8_t STATUS_LED_WARNING;
extern const uint8_t STATUS_LED_ERROR;
// Remove before 2026.8.0
enum class RetryResult { DONE, RETRY };
extern const uint16_t WARN_IF_BLOCKING_OVER_MS;
@@ -347,68 +348,40 @@ class Component {
bool cancel_interval(const char *name); // NOLINT
bool cancel_interval(uint32_t id); // NOLINT
/** Set an retry function with a unique name. Empty name means no cancelling possible.
*
* This will call the retry function f on the next scheduler loop. f should return RetryResult::DONE if
* it is successful and no repeat is required. Otherwise, returning RetryResult::RETRY will call f
* again in the future.
*
* The first retry of f happens after `initial_wait_time` milliseconds. The delay between retries is
* increased by multiplying by `backoff_increase_factor` each time. If no backoff_increase_factor is
* supplied (default = 1.0), the wait time will stay constant.
*
* The retry function f needs to accept a single argument: the number of attempts remaining. On the
* final retry of f, this value will be 0.
*
* This retry function can also be cancelled by name via cancel_retry().
*
* IMPORTANT: Do not rely on this having correct timing. This is only called from
* loop() and therefore can be significantly delayed.
*
* REMARK: It is an error to supply a negative or zero `backoff_increase_factor`, and 1.0 will be used instead.
*
* REMARK: The interval between retries is stored into a `uint32_t`, so this doesn't behave correctly
* if `initial_wait_time * (backoff_increase_factor ** (max_attempts - 2))` overflows.
*
* @param name The identifier for this retry function.
* @param initial_wait_time The time in ms before f is called again
* @param max_attempts The maximum number of executions
* @param f The function (or lambda) that should be called
* @param backoff_increase_factor time between retries is multiplied by this factor on every retry after the first
* @see cancel_retry()
*/
// Remove before 2026.7.0
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
/// @deprecated set_retry is deprecated. Use set_timeout or set_interval instead. Removed in 2026.8.0.
// Remove before 2026.8.0
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
"2026.2.0")
void set_retry(const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts, // NOLINT
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor = 1.0f); // NOLINT
// Remove before 2026.8.0
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
"2026.2.0")
void set_retry(const char *name, uint32_t initial_wait_time, uint8_t max_attempts, // NOLINT
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor = 1.0f); // NOLINT
/** Set a retry function with a numeric ID (zero heap allocation).
*
* @param id The numeric identifier for this retry function
* @param initial_wait_time The wait time after the first execution
* @param max_attempts The max number of attempts
* @param f The function to call
* @param backoff_increase_factor The factor to increase the retry interval by
*/
// Remove before 2026.8.0
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
"2026.2.0")
void set_retry(uint32_t id, uint32_t initial_wait_time, uint8_t max_attempts, // NOLINT
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor = 1.0f); // NOLINT
// Remove before 2026.8.0
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
"2026.2.0")
void set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std::function<RetryResult(uint8_t)> &&f, // NOLINT
float backoff_increase_factor = 1.0f); // NOLINT
/** Cancel a retry function.
*
* @param name The identifier for this retry function.
* @return Whether a retry function was deleted.
*/
// Remove before 2026.7.0
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
// Remove before 2026.8.0
ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
bool cancel_retry(const std::string &name); // NOLINT
bool cancel_retry(const char *name); // NOLINT
bool cancel_retry(uint32_t id); // NOLINT
// Remove before 2026.8.0
ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
bool cancel_retry(const char *name); // NOLINT
// Remove before 2026.8.0
ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
bool cancel_retry(uint32_t id); // NOLINT
/** Set a timeout function with a unique name.
*

View File

@@ -252,6 +252,11 @@ bool HOT Scheduler::cancel_interval(Component *component, uint32_t id) {
return this->cancel_item_(component, NameType::NUMERIC_ID, nullptr, id, SchedulerItem::INTERVAL);
}
// Suppress deprecation warnings for RetryResult usage in the still-present (but deprecated) retry implementation.
// Remove before 2026.8.0 along with all retry code.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
struct RetryArgs {
// Ordered to minimize padding on 32-bit systems
std::function<RetryResult(uint8_t)> func;
@@ -364,6 +369,8 @@ bool HOT Scheduler::cancel_retry(Component *component, uint32_t id) {
return this->cancel_retry_(component, NameType::NUMERIC_ID, nullptr, id);
}
#pragma GCC diagnostic pop // End suppression of deprecated RetryResult warnings
optional<uint32_t> HOT Scheduler::next_schedule_in(uint32_t now) {
// IMPORTANT: This method should only be called from the main thread (loop task).
// It performs cleanup and accesses items_[0] without holding a lock, which is only

View File

@@ -72,18 +72,30 @@ class Scheduler {
bool cancel_interval(Component *component, const char *name);
bool cancel_interval(Component *component, uint32_t id);
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
// Remove before 2026.8.0
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
"2026.2.0")
void set_retry(Component *component, const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts,
std::function<RetryResult(uint8_t)> func, float backoff_increase_factor = 1.0f);
// Remove before 2026.8.0
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
"2026.2.0")
void set_retry(Component *component, const char *name, uint32_t initial_wait_time, uint8_t max_attempts,
std::function<RetryResult(uint8_t)> func, float backoff_increase_factor = 1.0f);
/// Set a retry with a numeric ID (zero heap allocation)
// Remove before 2026.8.0
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
"2026.2.0")
void set_retry(Component *component, uint32_t id, uint32_t initial_wait_time, uint8_t max_attempts,
std::function<RetryResult(uint8_t)> func, float backoff_increase_factor = 1.0f);
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
// Remove before 2026.8.0
ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
bool cancel_retry(Component *component, const std::string &name);
// Remove before 2026.8.0
ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
bool cancel_retry(Component *component, const char *name);
// Remove before 2026.8.0
ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
bool cancel_retry(Component *component, uint32_t id);
// Calculate when the next scheduled item should run
@@ -231,11 +243,14 @@ class Scheduler {
uint32_t hash_or_id, uint32_t delay, std::function<void()> func, bool is_retry = false,
bool skip_cancel = false);
// Common implementation for retry
// Common implementation for retry - Remove before 2026.8.0
// name_type determines storage type: STATIC_STRING uses static_name, others use hash_or_id
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
void set_retry_common_(Component *component, NameType name_type, const char *static_name, uint32_t hash_or_id,
uint32_t initial_wait_time, uint8_t max_attempts, std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor);
#pragma GCC diagnostic pop
// Common implementation for cancel_retry
bool cancel_retry_(Component *component, NameType name_type, const char *static_name, uint32_t hash_or_id);