Concorrência e resiliência seguras de estilo direto para Scala na JVM. Requer JDK 21 e Scala 3. As áreas que gostaríamos de cobrir com OX são:
Todos os itens acima devem permitir a observabilidade da lógica de negócios orquestrada. Nosso objetivo é permitir a escrita de código simples e orientado para a expressão em estilo funcional. Gostaríamos de manter a sobrecarga de sintaxe no mínimo, preservando traços de pilha amigáveis ao desenvolvedor e sem comprometer o desempenho.
Alguns dos itens acima já estão abordados na API, outros estão chegando no futuro. Adoraríamos sua ajuda para moldar o projeto!
Para testar Ox, use a seguinte dependência, usando o SBT:
" com.softwaremill.ox " %% " core " % " 0.5.3 "
Ou scala-cli:
//> using dep " com.softwaremill.ox::core:0.5.3 "
A documentação está disponível em https://ox.softwaremill.com, o ScalAdocs pode ser navegado em https://javadoc.io.
Execute dois cálculos em paralelo:
def computation1 : Int = { sleep( 2 .seconds); 1 }
def computation2 : String = { sleep( 1 .second); " 2 " }
val result1 : ( Int , String ) = par(computation1, computation2)
// (1, "2")
Tempo limite um cálculo:
def computation3 : Int = { sleep( 2 .seconds); 1 }
val result2 : Either [ Throwable , Int ] = either.catching(timeout( 1 .second)(computation3))
// `timeout` only completes once the loosing branch is interrupted & done
Corrida dois cálculos:
def computation4 : Int = { sleep( 2 .seconds); 1 }
def computation5 : Int = { sleep( 1 .second); 2 }
val result3 : Int = raceSuccess(computation4, computation5)
// as before, the loosing branch is interrupted & awaited before returning a result
Concorrência e supervisão estruturadas:
// equivalent of par
supervised {
val f1 = fork { sleep( 2 .seconds); 1 }
val f2 = fork { sleep( 1 .second); 2 }
(f1.join(), f2.join())
}
Manipulação de erros dentro de um escopo de simultaneidade estruturado:
supervised {
forkUser :
sleep( 1 .second)
println( " Hello! " )
forkUser :
sleep( 500 .millis)
throw new RuntimeException ( " boom! " )
}
// on exception, all other forks are interrupted ("let it crash")
// the scope ends & re-throws only when all forks complete (no "leftovers")
Representar um cálculo:
def computationR : Int = ???
retry( RetryConfig .backoff( 3 , 100 .millis, 5 .minutes, Jitter . Equal ))(computationR)
Repita um cálculo:
def computationR : Int = ???
repeat( RepeatConfig .fixedRateForever( 100 .millis))(computationR)
Alocar um recurso em um escopo:
supervised {
val writer = useCloseableInScope( new java.io. PrintWriter ( " test.txt " ))
// ... use writer ...
} // writer is closed when the scope ends (successfully or with an error)
Crie um aplicativo que desliga de maneira limpa quando interrompida com SIGINT/SIGTERM:
object MyApp extends OxApp :
def run ( args : Vector [ String ])( using Ox ) : ExitCode =
// ... your app's code ...
// might use fork {} to create top-level background threads
ExitCode . Success
Atores simples seguros de tipo:
class Stateful { def increment ( delta : Int ) : Int = ??? }
supervised :
val ref = Actor .create( new Stateful )
// ref can be shared across forks, but only within the concurrency scope
ref.ask(_.increment( 5 ))
Crie um fluxo simples e transforme usando uma API funcional:
Flow .iterate( 0 )(_ + 1 ) // natural numbers
.filter(_ % 2 == 0 )
.map(_ + 1 )
.intersperse( 5 )
// compute the running total
.mapStateful(() => 0 ) { (state, value) =>
val newState = state + value
(newState, newState)
}
.take( 10 )
.runForeach(n => println(n.toString))
Crie fluxos que executem E/S e gerenciem simultaneidade:
def sendHttpRequest ( entry : String ) : Unit = ???
Flow
.fromInputStream( this .getClass().getResourceAsStream( " /list.txt " ))
.linesUtf8
.mapPar( 4 )(sendHttpRequest)
.runDrain()
Mesclar dois fluxos, lidando adequadamente com a falha de ambos os ramos:
val f1 = Flow .tick( 123 .millis, " left " )
val f2 = Flow .tick( 312 .millis, " right " )
f1.merge(f2).take( 100 ).runForeach(println)
Integre o fluxo com outros componentes usando uma API imperativa:
def readNextBatch () : List [ String ] = ???
Flow .usingEmit { emit =>
forever :
readNextBatch().foreach(emit.apply)
}
Use canais completos de alto desempenho para comunicação entre forros nos escopos de simultaneidade:
val c = Channel .buffered[ String ]( 8 )
c.send( " Hello, " )
c.send( " World " )
c.done()
Selecione entre canais do tipo GoC:
val c = Channel .rendezvous[ Int ]
val d = Channel .rendezvous[ Int ]
select(c.sendClause( 10 ), d.receiveClause)
Desembrulse os eitores e combine erros em um tipo de sindicato:
val v1 : Either [ Int , String ] = ???
val v2 : Either [ Long , String ] = ???
val result : Either [ Int | Long , String ] = either :
v1.ok() ++ v2.ok()
Valores de tubo e toque para funções para usar o Dot-Syntax:
def compute : Int = ???
def computeMore ( v : Int ) : Long = ???
compute
.pipe( 2 * _)
.tap(println)
.pipe(computeMore)
Mais nos documentos!.
O objetivo mais amplo do Scala de estilo direto está permitindo que as equipes entreguem o software de trabalho rapidamente e com confiança. Nossos outros projetos, incluindo o STTP Client e Tapir, também incluem integrações diretamente adaptadas ao estilo direto.
Além disso, também confira o projeto Gears, uma biblioteca experimental de várias plataformas também cobrindo o Scala de estilo direto.
Todas as sugestões são bem -vindas :)
Para compilar e testar, execute:
sbt compile
sbt test
Veja a lista de problemas e escolha um! Ou relatar o seu próprio.
Se você está tendo dúvidas sobre o porquê ou como algo funciona, não hesite em fazer uma pergunta sobre discurso ou via github. Provavelmente, isso significa que a documentação, scaladocs ou código não é clara e pode ser aprimorada para o benefício de todos.
Para desenvolver a documentação, você pode usar o script doc/watch.sh
, que executa o Sphinx usando o Python. Use doc/requirements.txt
para configurar seu ambiente Python com pip
. Como alternativa, se você é um usuário do NIX, execute nix develop
em doc/
para iniciar um shell com um ambiente, permitindo executar watch.sh
. Além disso, você pode usar a tarefa SBT compileDocumentation
para verificar se todos os trechos de código compilam corretamente.
Quando você tiver um PR pronto, dê uma olhada no nosso guia "Como preparar um bom PR". Obrigado! :)
Oferecemos serviços de desenvolvimento comercial. Entre em contato conosco para saber mais sobre nós!
Copyright (C) 2023-2024 Softwaremill https://softwaremill.com.