Glosario

Por qué el scheduled_at de la API de Mastodon necesita 5 minutos de margen

Taras Shynkarenko
Taras Shynkarenko
•Actualizado: •8 min de lectura
Por qué el scheduled_at de la API de Mastodon necesita 5 minutos de margenPor qué el scheduled_at de la API de Mastodon necesita 5 minutos de margen

TL;DR, Respuesta Rápida

8 min de lectura

Mastodon documenta scheduled_at como un valor que debe estar al menos 5 minutos en el futuro, y el código lo respalda con MINIMUM_OFFSET = 5.minutes en ScheduledStatus. Cualquier cosa más cercana devuelve un HTTP 422 con un error de validación. Una marca de tiempo en el pasado se comporta distinto: PostStatusService la descarta y publica el estado al instante. Otros dos límites, 300 estados programados en total y 25 por día, solo aparecen en el código.

¿Cuál es el margen mínimo de scheduled_at en la API de Mastodon?

Cada valor de scheduled_at de la API de Mastodon tiene que caer más de 5 minutos por delante del reloj del servidor, o POST /api/v1/statuses rechaza la petición con un HTTP 422. La documentación form-data de ese endpoint lo dice en una línea: "Datetime at which to schedule a status. Providing this parameter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."

El endpoint de actualización repite la regla con palabras algo distintas. PUT /api/v1/scheduled_statuses/:id documenta su propio scheduled_at como "Datetime at which the status will be published. Must be at least 5 minutes into the future", así que mover un post ya programado a menos de cinco minutos falla igual que crearlo.

El número no es una convención de la documentación. Es una constante del modelo, MINIMUM_OFFSET = 5.minutes.freeze en app/models/scheduled_status.rb, y la validación que la usa dice así:

def validate_future_date
  errors.add(:scheduled_at, I18n.t('scheduled_statuses.too_soon')) if scheduled_at.present? && scheduled_at <= Time.now.utc + MINIMUM_OFFSET
end

La comparación es <=, así que una marca de tiempo exactamente a 5 minutos falla. "At least 5 minutes" en la documentación significa estrictamente más de 5 minutos en el código.

¿Qué devuelve la API cuando la hora está demasiado cerca?

Un 422 con un mensaje de validación en el campo error. El manejo de errores de la API de Mastodon convierte la excepción de Rails directamente en JSON:

rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
  render json: { error: e.to_s }, status: 422
end

Ese concern vive en app/controllers/concerns/api/error_handling.rb y lo incluye Api::BaseController, así que el cuerpo es la cadena propia de la excepción y no un código legible por máquina. No hay código de error, ni lista de campos, ni pista de retry-after; interpretarlo significa hacer coincidir texto en inglés.

¿Por qué la cadena de error documentada difiere de la que envían los servidores?

Porque cambió la cadena de localización y el ejemplo de la documentación no. La página scheduled_statuses muestra este cuerpo 422 para el endpoint de actualización:

{
  "error": "Validation failed: Scheduled at The scheduled date must be in the future"
}

El config/locales/en.yml actual en la rama main de mastodon/mastodon lleva una frase más corta:

scheduled_statuses:
  over_daily_limit: You have exceeded the limit of %{limit} scheduled posts for today
  over_total_limit: You have exceeded the limit of %{limit} scheduled posts
  too_soon: date must be in the future

Rails antepone el nombre humanizado del atributo, así que un servidor actual produce "Validation failed: Scheduled at date must be in the future". El ejemplo documentado sigue arrastrando la redacción antigua, "The scheduled date must be in the future".

FuenteCadena
docs.joinmastodon.org, ejemplo 422 de scheduled_statuses"Validation failed: Scheduled at The scheduled date must be in the future"
config/locales/en.yml, rama main"Validation failed: Scheduled at date must be in the future"

Cualquier cliente que compare la frase documentada al pie de la letra no detectará el error en un servidor actual. Compara contra el estado 422 y contra la presencia de scheduled_at en tu propia petición en lugar de contra la frase.

Una persona mira la hora en su teléfono, una imagen de cómo el destino de una publicación programada depende de una sola marca de tiempo.

¿Qué pasa si scheduled_at está en el pasado?

El post sale al instante y no se lanza ningún error. Este es el comportamiento que la documentación nunca menciona, y vive en PostStatusService:

@scheduled_at = @options[:scheduled_at]&.to_datetime
@scheduled_at = nil if scheduled_in_the_past?

con

def scheduled_in_the_past?
  @scheduled_at.present? && @scheduled_at <= Time.now.utc
end

Poner @scheduled_at a nil hace que scheduled? sea falso, lo que encamina la petición por process_status! en lugar de por schedule_status!. La respuesta es una entidad Status, no un ScheduledStatus, así que un cliente que dé por hecho que scheduled_at siempre produce un ScheduledStatus leerá un id ausente para un post que ya es público.

Tres resultados, un parámetro:

AdaptlyPost
AdaptlyPost

Empieza tu prueba gratis de 7 días

Analíticas multiplataforma

Bandeja Social

Asistente con IA

Valor de scheduled_atResultadoRespuesta
En el pasado, o exactamente ahoraPublicado al instanteStatus
Dentro de los 5 minutos siguientesRechazado422, error de validación
A más de 5 minutos vistaEn colaScheduledStatus

La banda del medio es la trampa. Un bucle de reintentos que empuja un envío fallido "un par de minutos más tarde" se mete de lleno en el 422; uno que recurre a "publícalo ya" enviando una marca de tiempo pasada consigue un post en vivo en lugar del error que esperaba.

La trampa del reintento
Reintentar unos minutos después
  • Cae dentro de la franja de 5 minutos
  • El servidor responde con 422
Recurrir a "publicar ahora"
  • Envía una marca de tiempo en el pasado
  • PostStatusService descarta scheduled_at
  • El estado se publica de inmediato
Dos reacciones habituales a un envío fallido, y ninguna produce el resultado que esperaba quien lo envió.

¿Cuántos estados programados puede tener una cuenta?

Otros dos límites se sientan junto al margen en el mismo modelo, y ninguno aparece en la documentación de la API:

TOTAL_LIMIT = 300
DAILY_LIMIT = 25
MINIMUM_OFFSET = 5.minutes.freeze

TOTAL_LIMIT limita cuántos estados programados puede tener en cola una cuenta a la vez, y el mensaje es "You have exceeded the limit of 300 scheduled posts". DAILY_LIMIT limita cuántos pueden compartir una misma fecha del calendario, validado con scheduled_at::date = ?::date contra la base de datos, y el mensaje es "You have exceeded the limit of 25 scheduled posts for today".

Los dos llegan con la misma forma de 422, con el mensaje en base y no en scheduled_at. Una cola que carga un mes de posts de una sola vez chocará con el muro de 25 por día mucho antes que con el total de 300, y nada en docs.joinmastodon.org avisa de ninguno de los dos.

¿Qué formato admite scheduled_at?

Una fecha y hora RFC 3339, que Mastodon documenta aparte como su formato de datetime: [YYYY]-[MM]-[DD]T[hh]:[mm]:[ss].[s][TZD], donde el designador de zona horaria es o bien Z para UTC o bien un desplazamiento como +02:00. La documentación es explícita en que el separador es una T mayúscula y en que la Z va siempre en mayúscula.

La validación compara contra Time.now.utc en el servidor, no en el cliente. La deriva del reloj del cliente se come por tanto directamente el margen de cinco minutos, que es una buena razón para programar a seis o siete minutos vista en lugar de a cinco minutos y un segundo. El mismo modo de fallo aparece siempre que una cola se fía de la hora local, como pasa entre Mastodon y Bluesky y en cualquier otra API que valide contra su propio reloj.

Un calendario de pared sobre un escritorio representa la cola de publicaciones programadas que gestiona una cuenta con el tiempo.

¿Cómo se cambia o se cancela un estado programado?

Tres endpoints gestionan la cola después de crearla. GET /api/v1/scheduled_statuses los lista, con 20 resultados por defecto y un máximo de 40. PUT /api/v1/scheduled_statuses/:id acepta un scheduled_at nuevo, sujeto a la misma regla de 5 minutos. DELETE /api/v1/scheduled_statuses/:id cancela uno y devuelve un objeto vacío.

Cambiar el texto es otra operación. Mastodon señala que PUT /api/v1/statuses/:id edita un estado publicado, y que "To edit the scheduled_at attribute of a ScheduledStatus to change the publication date, use the scheduled status endpoint." El contenido de un post en cola vive en el objeto params de la entidad ScheduledStatus y el endpoint de actualización solo acepta la fecha, así que cambiar la redacción significa borrar y volver a crear.

Un estado en cola que ya no existe devuelve 404 con {"error": "Record not found"}, que es también lo que devuelve un estado programado que pertenece a otra cuenta.

¿Qué significa el suelo de 5 minutos para una cola de publicación?

Fija el hueco útil más corto entre "decidir publicar" y "publicar". Cualquier cosa por debajo de cinco minutos hay que enviarla como estado inmediato y no como programado, así que un programador necesita una bifurcación, no un único camino de código: por debajo del umbral, quita scheduled_at y publica; por encima, encola y guarda el id del ScheduledStatus devuelto.

Otros dos números entran en la misma planificación. La longitud de post por defecto de Mastodon es de 500 caracteres, cubierta en el límite de caracteres de Mastodon, y el límite de tasa por servidor se apila encima de todo ello, igual que Bluesky publica sus propios límites de tasa de la API aparte de sus reglas de posts. Construir el calendario alrededor del suelo de la plataforma y no de las preferencias de una herramienta es el hábito general detrás de programar posts en redes sociales de forma fiable.

Una advertencia cubre todos los números de arriba. Las constantes vienen de la rama main de mastodon/mastodon, y un servidor que corra un fork o una versión antigua puede llevar valores distintos, así que lee el cuerpo del 422 en lugar de dar por hecho que 5, 25 y 300 valen en todas partes.

Preguntas frecuentes

¿scheduled_at acepta una hora exactamente a 5 minutos vista?

No. La validación compara con <=, así que scheduled_at <= Time.now.utc + 5.minutes falla. La frase documentada "at least 5 minutes in the future" significa estrictamente más de cinco minutos en cuanto lees el código fuente.

¿Qué estado HTTP devuelve Mastodon para un scheduled_at demasiado cercano?

  1. Mastodon rescata ActiveRecord::RecordInvalid y renderiza { error: e.to_s } con estado 422, así que el cuerpo es una frase de validación en inglés llano y no un objeto de error estructurado.

¿Qué versión de Mastodon añadió scheduled_at?

La 2.7.0. El historial de versiones de la documentación de POST /api/v1/statuses lista "2.7.0 - scheduled_at added", y los tres endpoints de scheduled_statuses se añadieron en la misma entrega.

AdaptlyPost
AdaptlyPost

Empieza tu prueba gratis de 7 días

Analíticas multiplataforma

Bandeja Social

Asistente con IA

¿Un post programado devuelve un Status o un ScheduledStatus?

Un ScheduledStatus, siempre que se acepte scheduled_at. Mastodon afirma que el endpoint "Returns: Status. When scheduled_at is present, ScheduledStatus is returned instead." Una marca de tiempo pasada es la excepción, porque el servidor descarta el parámetro y publica al instante, devolviendo un Status.

¿Se pueden programar más de 25 posts de Mastodon para el mismo día?

En un servidor por defecto, no. DAILY_LIMIT = 25 en app/models/scheduled_status.rb cuenta los estados programados que ya comparten la misma fecha y rechaza el vigesimosexto con "You have exceeded the limit of 25 scheduled posts for today". Un TOTAL_LIMIT = 300 aparte limita toda la cola. Ninguno de los dos números aparece en la documentación de la API.

¿Dónde está documentado el mínimo de 5 minutos?

En la página de métodos de la API statuses, en docs.joinmastodon.org/methods/statuses/, dentro del parámetro form-data scheduled_at, y otra vez en docs.joinmastodon.org/methods/scheduled_statuses/ para el endpoint de actualización. La constante que hay detrás es MINIMUM_OFFSET = 5.minutes.freeze en app/models/scheduled_status.rb en el repositorio mastodon/mastodon.

¿Cuántos resultados devuelve GET /api/v1/scheduled_statuses por defecto?

Veinte. El endpoint devuelve 20 estados programados por página de forma predeterminada, con un máximo de 40, así que una cuenta cerca del límite total de 300 necesita varias solicitudes para recorrer toda su cola.

¿Qué pasa si consultas un estado programado que ya cancelaste?

El servidor responde con 404 y {"error": "Record not found"}. Es la misma respuesta que recibe un estado programado que pertenece a otra cuenta, así que un 404 aquí no distingue entre "nunca existió", "ya se canceló" y "no es tuyo".

¿Se puede editar el texto de un estado programado en Mastodon?

Editar el texto significa borrar el estado programado y crear uno nuevo, no modificarlo en su sitio. El endpoint de actualización solo acepta un nuevo scheduled_at, y el contenido de un estado en cola vive en el objeto params de la entidad ScheduledStatus.

¿Con cuánta antelación conviene programar realmente un post en Mastodon?

Más de cinco minutos, aunque seis o siete minutos son más seguros que cinco minutos y un segundo. La validación se compara contra el reloj del servidor, no el del cliente, así que cualquier desfase de la hora local consume directamente ese margen.

¿Te resultó útil este artículo?

¡Cuéntanos qué te parece!

Vernos más en Google

Un clic marca AdaptlyPost como fuente preferida y nuestros artículos aparecen más arriba en tus Noticias destacadas, el modo IA y los resúmenes con IA.

Antes de irte...

AdaptlyPost

AdaptlyPost

Programa tu contenido en todas las plataformas

Gestiona todas tus cuentas de redes sociales en un solo lugar con AdaptlyPost.

Analíticas multiplataforma

Bandeja Social

Asistente con IA

Términos relacionados del glosario

Artículos Relacionados