Glossário

Por que o scheduled_at da API do Mastodon precisa de 5 minutos de folga

Taras Shynkarenko
Taras Shynkarenko
•Atualizado: •8 min de leitura
Por que o scheduled_at da API do Mastodon precisa de 5 minutos de folgaPor que o scheduled_at da API do Mastodon precisa de 5 minutos de folga

TL;DR, Resposta Rápida

8 min de leitura

O Mastodon documenta que o scheduled_at precisa estar pelo menos 5 minutos no futuro, e o código sustenta isso com MINIMUM_OFFSET = 5.minutes em ScheduledStatus. Qualquer coisa mais perto devolve HTTP 422 com um erro de validação. Um timestamp no passado se comporta de outro jeito: o PostStatusService descarta o valor e publica o status na hora. Outros dois limites, 300 status agendados no total e 25 por dia, aparecem só no código-fonte.

Qual é o offset mínimo de scheduled_at na API do Mastodon?

Todo valor de scheduled_at da API do Mastodon precisa cair mais de 5 minutos à frente do relógio do servidor, senão POST /api/v1/statuses rejeita a requisição com HTTP 422. A documentação de form-data desse endpoint diz isso em uma linha: "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."

O endpoint de atualização repete a regra com palavras um pouco diferentes. O PUT /api/v1/scheduled_statuses/:id documenta o próprio scheduled_at como "Datetime at which the status will be published. Must be at least 5 minutes into the future", então mover um post já agendado para menos de cinco minutos falha do mesmo jeito que criar um.

O número não é uma convenção de documentação. É uma constante no modelo, MINIMUM_OFFSET = 5.minutes.freeze em app/models/scheduled_status.rb, e a validação que a usa é esta:

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

A comparação é <=, então um timestamp exatamente 5 minutos à frente falha. "At least 5 minutes" na documentação significa estritamente mais de 5 minutos no código.

O que a API devolve quando o horário está perto demais?

Um 422 com uma mensagem de validação no campo error. O tratamento de erros da API do Mastodon transforma a exceção do Rails direto em JSON:

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

Esse concern vive em app/controllers/concerns/api/error_handling.rb e é incluído pelo Api::BaseController, então o corpo é a string da própria exceção, e não um código legível por máquina. Não há código de erro, lista de campos nem dica de retry-after; interpretar isso significa casar com texto em inglês.

Por que a string de erro documentada difere da que os servidores enviam?

Porque a string de locale mudou e o exemplo da documentação não. A página scheduled_statuses mostra este corpo de 422 para o endpoint de atualização:

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

O config/locales/en.yml atual na branch main de mastodon/mastodon traz uma frase mais curta:

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

O Rails prefixa o nome humanizado do atributo, então um servidor atual produz "Validation failed: Scheduled at date must be in the future". O exemplo documentado ainda carrega a redação antiga, "The scheduled date must be in the future".

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

Qualquer cliente que compare exatamente com a frase documentada vai perder o erro em um servidor atual. Compare pelo status 422 e pela presença de scheduled_at na sua própria requisição, não pela frase.

Uma pessoa confere as horas no celular, uma imagem de como o destino de uma publicação agendada depende de uma única marcação de tempo.

O que acontece se o scheduled_at estiver no passado?

O post sai na hora, e nenhum erro é levantado. Esse é o comportamento que a documentação nunca menciona, e ele vive no PostStatusService:

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

com

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

Definir @scheduled_at como nil faz scheduled? ser falso, o que leva a requisição por process_status! em vez de schedule_status!. A resposta é uma entidade Status, não ScheduledStatus, então um cliente que presume que scheduled_at sempre devolve um ScheduledStatus vai ler um id ausente para um post que já está público.

Três resultados, um parâmetro:

AdaptlyPost
AdaptlyPost

Comece seu teste grátis de 7 dias

Análises multiplataforma

Caixa Social

Assistente com IA

Valor de scheduled_atResultadoResposta
No passado, ou exatamente agoraPublicado na horaStatus
Dentro de 5 minutos a partir de agoraRejeitado422, erro de validação
Mais de 5 minutos à frenteEnfileiradoScheduledStatus

A faixa do meio é a armadilha. Um loop de retry que empurra um envio falho para "alguns minutos depois" cai direto no 422; um que recorre a publicar agora mandando um timestamp no passado ganha um post ao vivo em vez do erro que esperava.

A armadilha da nova tentativa
Tentar de novo alguns minutos depois
  • Cai dentro da faixa de 5 minutos
  • O servidor responde com 422
Recorrer a "publicar agora"
  • Envia um timestamp no passado
  • PostStatusService descarta scheduled_at
  • O status é publicado imediatamente
Duas reações comuns a um envio que falhou, e nenhuma delas dá o resultado esperado.

Quantos status agendados uma conta pode manter?

Mais dois limites ficam ao lado do offset no mesmo modelo, e nenhum dos dois aparece na documentação da API:

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

O TOTAL_LIMIT limita quantos status agendados uma conta pode ter na fila ao mesmo tempo, e a mensagem é "You have exceeded the limit of 300 scheduled posts". O DAILY_LIMIT limita quantos podem dividir a mesma data do calendário, validado com scheduled_at::date = ?::date contra o banco, e a mensagem é "You have exceeded the limit of 25 scheduled posts for today".

Os dois chegam no mesmo formato de 422, com a mensagem em base e não em scheduled_at. Uma fila que carrega um mês de posts de uma vez bate na parede dos 25 por dia muito antes dos 300 no total, e nada em docs.joinmastodon.org avisa sobre nenhum dos dois.

Que formato o scheduled_at aceita?

Um datetime RFC 3339, que o Mastodon documenta à parte como seu formato de data e hora: [YYYY]-[MM]-[DD]T[hh]:[mm]:[ss].[s][TZD], em que o designador de fuso é Z para UTC ou um offset como +02:00. A documentação é explícita ao dizer que o separador é um T maiúsculo e que o Z é sempre maiúsculo.

A validação compara contra Time.now.utc no servidor, não no cliente. O desvio do relógio do cliente come direto da margem de cinco minutos, o que é um bom motivo para agendar a seis ou sete minutos em vez de cinco minutos e um segundo. O mesmo modo de falha aparece sempre que uma fila confia no horário local, como acontece entre Mastodon e Bluesky e em qualquer outra API que valida contra o próprio relógio.

Um calendário de parede sobre uma mesa representa a fila de publicações agendadas que uma conta administra ao longo do tempo.

Como mudar ou cancelar um status agendado?

Três endpoints cuidam da fila depois da criação. O GET /api/v1/scheduled_statuses lista os agendamentos, com 20 resultados por padrão e máximo de 40. O PUT /api/v1/scheduled_statuses/:id recebe um novo scheduled_at, sujeito à mesma regra de 5 minutos. O DELETE /api/v1/scheduled_statuses/:id cancela um e devolve um objeto vazio.

Mudar o texto é outra operação. O Mastodon observa que PUT /api/v1/statuses/:id edita um status já publicado, e que "To edit the scheduled_at attribute of a ScheduledStatus to change the publication date, use the scheduled status endpoint." O conteúdo de um post na fila vive no objeto params da entidade ScheduledStatus e o endpoint de atualização aceita apenas a data, então mudar a redação significa apagar e recriar.

Um status na fila que não existe mais devolve 404 com {"error": "Record not found"}, que é também o que devolve um status agendado pertencente a outra conta.

O que o piso de 5 minutos significa para uma fila de publicação?

Ele define o menor intervalo útil entre decidir postar e postar. Qualquer coisa abaixo de cinco minutos precisa sair como status imediato e não como agendado, então um agendador precisa de um desvio, e não de um caminho único: abaixo do limite, descarte o scheduled_at e publique; acima dele, enfileire e guarde o id do ScheduledStatus devolvido.

Outros dois números pertencem à mesma rodada de planejamento. O tamanho padrão de post do Mastodon é de 500 caracteres, coberto em o limite de caracteres do Mastodon, e o rate limiting por servidor fica por cima de tudo isso, do mesmo jeito que o Bluesky publica os próprios rate limits de API separadamente das regras de post. Montar o calendário em torno do piso da plataforma, e não das preferências de uma ferramenta, é o hábito geral por trás de agendar posts em redes sociais com confiabilidade.

Uma ressalva cobre todos os números acima. As constantes vêm da branch main de mastodon/mastodon, e um servidor rodando um fork ou uma versão mais antiga pode ter valores diferentes, então leia o corpo do 422 em vez de presumir que 5, 25 e 300 valem em todo lugar.

Perguntas frequentes

O scheduled_at aceita um horário exatamente 5 minutos à frente?

Não. A validação compara com <=, então scheduled_at <= Time.now.utc + 5.minutes falha. A frase documentada "at least 5 minutes in the future" significa estritamente mais de cinco minutos quando você lê o código-fonte.

Que status HTTP o Mastodon devolve para um scheduled_at cedo demais?

  1. O Mastodon resgata ActiveRecord::RecordInvalid e renderiza { error: e.to_s } com status 422, então o corpo é uma frase de validação em inglês simples em vez de um objeto de erro estruturado.

Qual versão do Mastodon adicionou o scheduled_at?

2.7.0. O histórico de versões na documentação de POST /api/v1/statuses lista "2.7.0 - scheduled_at added", e os três endpoints de scheduled_statuses entraram no mesmo release.

AdaptlyPost
AdaptlyPost

Comece seu teste grátis de 7 dias

Análises multiplataforma

Caixa Social

Assistente com IA

Um post agendado devolve um Status ou um ScheduledStatus?

Um ScheduledStatus, sempre que o scheduled_at é aceito. O Mastodon afirma que o endpoint "Returns: Status. When scheduled_at is present, ScheduledStatus is returned instead." A exceção é um timestamp no passado, porque o servidor descarta o parâmetro e publica na hora, devolvendo um Status.

Dá para agendar mais de 25 posts do Mastodon para o mesmo dia?

Não em um servidor padrão. O DAILY_LIMIT = 25 em app/models/scheduled_status.rb conta os status agendados que já dividem a mesma data e rejeita o vigésimo sexto com "You have exceeded the limit of 25 scheduled posts for today". Um TOTAL_LIMIT = 300 separado limita a fila inteira. Nenhum dos dois números aparece na documentação da API.

Onde o mínimo de 5 minutos está documentado?

Na página de métodos de statuses em docs.joinmastodon.org/methods/statuses/, no parâmetro de form-data scheduled_at, e de novo em docs.joinmastodon.org/methods/scheduled_statuses/ para o endpoint de atualização. A constante por trás dele é MINIMUM_OFFSET = 5.minutes.freeze em app/models/scheduled_status.rb no repositório mastodon/mastodon.

Quantos resultados o GET /api/v1/scheduled_statuses devolve por padrão?

Vinte. O endpoint devolve 20 status agendados por página por padrão, com um máximo de 40, então uma conta perto do limite total de 300 precisa de várias requisições para percorrer toda a fila.

O que acontece se você consultar um status agendado que já foi cancelado?

O servidor responde com 404 e {"error": "Record not found"}. É a mesma resposta de um status agendado que pertence a outra conta, então um 404 aqui não diferencia entre "nunca existiu", "já foi cancelado" e "não é seu".

Dá para editar o texto de um status agendado no Mastodon?

Editar o texto significa apagar o status agendado e criar um novo, não modificá-lo no lugar. O endpoint de atualização só aceita um novo scheduled_at, e o conteúdo de um status na fila vive no objeto params da entidade ScheduledStatus.

Com quanto tempo de antecedência você deveria realmente agendar um post no Mastodon?

Mais de cinco minutos, e seis ou sete minutos são mais seguros do que cinco minutos e um segundo. A validação compara com o relógio do servidor, não com o do cliente, então qualquer atraso no horário local corrói exatamente essa margem.

Este artigo foi útil para você?

Conte-nos o que você achou!

Veja-nos mais no Google

Um clique marca a AdaptlyPost como fonte preferida e nossos artigos passam a aparecer mais acima nas suas Principais notícias, no modo IA e nas visões gerais com IA.

Antes de ir...

AdaptlyPost

AdaptlyPost

Agende seu conteúdo em todas as plataformas

Gerencie todas as suas contas de redes sociais em um só lugar com o AdaptlyPost.

Análises multiplataforma

Caixa Social

Assistente com IA

Termos relacionados do glossário

Artigos Relacionados