← SWIFT: decisões de suporte e projetos bancários
09 / 10 · 60 MIN

Oficina: filas, capacidade e recuperação funcional

Calcular atraso durante manutenção, testar sensibilidade, observar idade e identidades e distinguir disponibilidade técnica de recuperação funcional.

Fixar o modelo e a unidade

O laboratório representa trabalho sintético numa fila FIFO em memória. Cada item é uma unidade de trabalho, sem montante, contraparte ou mensagem financeira. Existem vinte itens iniciais, entrados no instante menos cinco. A manutenção começa em zero e dura dez minutos. Chegam quatro itens no início de cada intervalo; depois da pausa, podem ser processados oito, concluindo no fim do intervalo. Esta convenção é parte do exercício e deve acompanhar os resultados. FIFO não é apresentado como requisito Swift. O código usa deque para conservar a ordem e não se liga a qualquer infraestrutura bancária.

Calcular a margem necessária

Durante a pausa acumulam-se quarenta itens novos, ficando sessenta. Depois chegam quatro por minuto enquanto oito são processados. A margem líquida é quatro, pelo que a drenagem demora quinze minutos e o tempo total é vinte e cinco. Dividir sessenta por oito ignoraria as chegadas em curso. Se a capacidade for igual a quatro, a fila deixa de crescer mas não diminui neste modelo. Para sessenta e um itens, reservar dezasseis intervalos completos. A função usa Fraction e arredondamento para cima, evitando que o último item desapareça por truncagem na estimativa. Todos estes valores são pressupostos didáticos, sem medição de capacidade Swift.

Examinar sensibilidade e limites

Aumentar chegadas para seis muda dois termos: acumula oitenta itens durante a pausa e deixa só dois por minuto para recuperar. O total passa a cinquenta minutos. Aumentar apenas a pausa para doze minutos, mantendo chegadas quatro, dá sessenta e oito itens e dezassete minutos de drenagem, num total de vinte e nove. Uma pequena demora técnica pode, assim, criar uma demora funcional maior. A projeção presume taxas constantes e trabalho equivalente. Picos, retries, prioridades, bloqueios e consumidores seguintes exigem modelação e medições próprias. O PM deve levar estes pressupostos à reunião em vez de apresentar um único número como garantia.

Observar idade e preservar identidades

Ao minuto dez, o item mais antigo tem quinze minutos de idade. Os primeiros oito itens terminam em onze, os oito seguintes em doze e os quatro antigos restantes em treze, com idade dezoito. A fila total ainda existe ao minuto vinte e só fica vazia em vinte e cinco. O relatório distingue estes marcos e usa ausência de idade quando não há itens. Também confirma cento e vinte identidades concluídas: vinte iniciais mais cem chegadas. Contagem igual pode esconder uma repetição e uma falta, por isso comparar conjuntos. Conclusão de trabalho no simulador não significa liquidação nem aceitação de uma mensagem real.

Demonstrar recuperação para o negócio

Num incidente fictício APS, o processo volta ao minuto dez, mas o acordo local exige dados atuais, resultados conhecidos e fila dentro do limite. Se o objetivo funcional for quinze minutos, o cenário de vinte e cinco falha esse compromisso. O relatório deve preservar a diferença e atribuir responsáveis aos desconhecidos. A orientação NIST sobre reconstituição distingue validação de dados e de funcionalidade; aqui serve como referência geral, sem impor uma regra bancária. Verificar também a etapa seguinte: oito itens por minuto no primeiro consumidor não bastam se a confirmação final só consegue cinco. O critério deve corresponder ao resultado realmente prometido.

Executar e transportar o raciocínio

Reservar quinze minutos para prever saldos e idades, vinte para executar e alterar uma taxa, quinze para explicar a diferença e dez para preparar uma nota em inglês. O programa completo grava 41 verificações com versão do Python e hash do código. Inclui também os critérios de evidência da aula seguinte. As taxas calculadas não substituem ensaios representativos e autorizados. A Swift indica que desempenho e disponibilidade do ITB não equivalem a produção e exclui testes de desempenho ou stress nesse ambiente. Guardar pressupostos e limites junto do resultado permite a outro colega repetir a análise sem transformar números inventados em SLA.

"""DR original synthetic queue and change-evidence exercises, Python 3.13.
python3 run.py --output evidence.json
No Swift network, production benchmark, CSCF implementation or real approval.
Rates, timings, evidence labels and readiness gates are teaching assumptions.
"""
import argparse
from collections import deque
from fractions import Fraction
import hashlib
import json
import math
from pathlib import Path
import sys

checks=[]
def check(name,actual,expected):
    assert actual==expected,(name,actual,expected)
    checks.append(dict(name=name,actual=actual,expected=expected,passed=True))

def drain_minutes(backlog,arrivals,capacity):
    if min(backlog,arrivals,capacity)<0:raise ValueError('negative input')
    if backlog==0:return 0
    if capacity<=arrivals:return None
    return math.ceil(Fraction(backlog,capacity-arrivals))

def simulate(initial,initial_at,arrivals,capacities):
    # Each slot is [t,t+1): arrivals at t, FIFO processing finishes at t+1.
    # A processed work item is NOT a settled financial transaction.
    if initial_at>0 or min(initial,arrivals,*capacities)<0:raise ValueError('invalid schedule')
    queue=deque((f'old-{i}',initial_at) for i in range(initial))
    trace=[];done=[]
    for t,capacity in enumerate(capacities):
        queue.extend((f'new-{t}-{i}',t) for i in range(arrivals))
        processed=[]
        for _ in range(min(capacity,len(queue))):
            identity,entered=queue.popleft()
            processed.append(dict(id=identity,entered=entered,finished=t+1,age=t+1-entered))
        done.extend(processed)
        trace.append(dict(end=t+1,backlog=len(queue),processed=len(processed),oldestAge=t+1-queue[0][1] if queue else None))
    return dict(trace=trace,done=done,pending=list(queue))

def reuse_candidate(assessor_agrees,significant_change,uncovered_control_change,prior_reuses):
    # Models public FAQ prerequisites only; True is not a compliance decision.
    return assessor_agrees and not significant_change and not uncovered_control_change and prior_reuses==0

def evidence_binding(candidate,report):
    # Original conservative local gate, not a Swift-mandated record format.
    return all(candidate[k]==report[k] for k in ('build','environment','footprint','controls')) and report['observed'] is True

def recovery_gate(service_up,reference_current,observations_complete,backlog,limit,owner_accepts):
    return service_up and reference_current and observations_complete and backlog<=limit and owner_accepts

def main():
    check('maintenance accumulation',20+4*10,60)
    check('net drain rate',8-4,4)
    check('drain duration',drain_minutes(60,4,8),15)
    check('total recovery duration',10+drain_minutes(60,4,8),25)
    check('rounded drain duration',drain_minutes(61,4,8),16)
    check('equal capacity cannot drain',drain_minutes(60,4,4),None)
    check('lower capacity cannot drain',drain_minutes(60,4,3),None)
    check('empty backlog needs no drain',drain_minutes(0,4,8),0)
    check('higher arrivals extend recovery',10+drain_minutes(20+6*10,6,8),50)
    check('longer maintenance extends recovery',12+drain_minutes(20+4*12,4,8),29)
    base=simulate(20,-5,4,[0]*10+[8]*15)
    check('queue at maintenance end',base['trace'][9]['backlog'],60)
    check('oldest age at maintenance end',base['trace'][9]['oldestAge'],15)
    check('first resumed slot backlog',base['trace'][10]['backlog'],56)
    check('queue still present at minute twenty',base['trace'][19]['backlog'],20)
    check('queue clear at minute twenty five',base['trace'][24]['backlog'],0)
    check('empty queue has no oldest age',base['trace'][24]['oldestAge'],None)
    check('processed identities unique',len({x['id'] for x in base['done']}),120)
    check('all expected work accounted',len(base['done'])+len(base['pending']),20+4*25)
    check('first original item completes',base['done'][0]['finished'],11)
    check('maximum item age',max(x['age'] for x in base['done']),18)
    check('fifo original work first',all(x['id'].startswith('old-') for x in base['done'][:20]),True)
    check('fast component does not meet functional target',10<=15 and 25>15,True)
    check('local latest rollback start',40-12-8-5,15)
    check('local rollback boundary allowed',15+12+8+5<=40,True)
    check('one minute delay misses local boundary',16+12+8+5<=40,False)
    check('reuse prerequisite set satisfied',reuse_candidate(True,False,False,0),True)
    check('assessor agreement missing',reuse_candidate(False,False,False,0),False)
    check('significant footprint change prevents reuse',reuse_candidate(True,True,False,0),False)
    check('uncovered control change prevents reuse',reuse_candidate(True,False,True,0),False)
    check('second consecutive reuse prevented',reuse_candidate(True,False,False,1),False)
    candidate=dict(build='dr-7',environment='QUALIFICATION',footprint='fp-2',controls='scope-3')
    report={**candidate,'observed':True}
    check('matching evidence binding',evidence_binding(candidate,report),True)
    for key in candidate:
        check('changed '+key+' invalidates local binding',evidence_binding(candidate,{**report,key:'different'}),False)
    check('planned evidence is insufficient',evidence_binding(candidate,{**report,'observed':False}),False)
    check('complete local recovery gate',recovery_gate(True,True,True,0,0,True),True)
    check('running process alone insufficient',recovery_gate(True,False,False,20,0,False),False)
    check('unknown observations prevent closure',recovery_gate(True,True,False,0,0,True),False)
    check('backlog limit prevents closure',recovery_gate(True,True,True,1,0,True),False)
    check('acceptance authority still required',recovery_gate(True,True,True,0,0,False),False)
    evidence=dict(scope='Original deterministic FIFO and local evidence models, not production capacity, Swift traffic, security compliance, institutional approval or financial settlement.',python=sys.version.split()[0],runnerSha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),passed=len(checks),checks=checks)
    parser=argparse.ArgumentParser();parser.add_argument('--output',required=True)
    Path(parser.parse_args().output).write_text(json.dumps(evidence,indent=2)+'\n')
    print(json.dumps({'passed':len(checks),'scope':evidence['scope']}))
if __name__=='__main__':main()
NA PRÁTICA

Caso: prolongar a pausa de dez para doze minutos aumenta a recuperação total de 25 para 29. Os dois minutos adicionais também criam atraso a drenar.

Armadilhas comuns

Dividir atraso por capacidade bruta; reiniciar a idade na recuperação; contar repetições como novas conclusões; inferir capacidade de produção do ITB.

Tópicos relacionados: Estados, reconciliação e recuperação sem duplicar · Segurança, âmbito e evidência independente · Continuidade e passagem à operação

Leva esta ideia contigo

Recuperação exige capacidade líquida e critérios funcionais observáveis, com identidades, tempos, pressupostos e autoridade explícitos.

Criar conta

Referência: Python collections: deque · DR Swift knowledge assessment2026.10; independent professional curriculum

SWIFT® é uma marca registada de S.W.I.F.T. SC. A dr.pt é uma plataforma de preparação independente e não está afiliada, associada, patrocinada, autorizada nem aprovada por Swift. Os conteúdos e as perguntas são originais, não são perguntas oficiais de exame, e concluir os nossos testes não atribui nem garante qualquer certificação. Os nomes são usados apenas para identificar o tema. Todas as outras marcas pertencem aos respetivos titulares.