Channelã¹ã¿ã¤ã«ã®ä¸¦è¡å¦çã®è¨è¿°ã(ãã¡ããåå®å ¨ã«)å¯è½ã«ããã©ã¤ãã©ãªOxã«ã¤ãã¦èª¿ã¹ã¦è©¦ãã¦ã¿ããçµè«ããè¨ãã¨æ¸ãå³ããã¡ããã¡ãè¯ãã¦é¢ç½ãã
ã½ã¼ã¹ã³ã¼ããç½®ãã¦ããã
Ox
Oxã¨ã¯ãsttpãªã©ã®éçºã§ã馴æã®SoftwareMillã«ãã£ã¦éçºããã¦ããScalaç¨ã®éåæã©ã¤ãã©ãªã§ãããã¾ã é常ã«è¥ããæ´»çºã«éçºããã¦ããã
Oxã®ç¹å¾´ã¯ãã¨ãããç®çã¨ãã£ã¦ãå·®ãæ¯ããªãã®ã ããããã¯Channelæåã®éåæå¦çãã¤ã¾ãGoroutineãScalaã®ä¸ã§å®ç¾ãã¦ããç¹ã ãGoã¦ã¼ã¶ãªãããã«ç解ã§ããã ããã
ç¾èã¯ä¸è¦ã«å¦ããããããªæãã®ã³ã¼ããæ¸ããã¨ãã§ãã(v0.0.25æç¹)ã
import ox.* import ox.channels.* import scala.concurrent.duration.* def channels = // ãã£ã³ãã«ãä½æãrendezvousãã£ã³ãã«ã¯Goroutineã§ããã¨ããã®ããããã¡ç¡ããã£ã³ãã«ãã®ãã¨ã // ãã¡ãããããã¡ä»ããã£ã³ãã«ããã(å²æ)ã val chan1 = Channel.rendezvous[String] val chan2 = Channel.rendezvous[String] // supervisedã§å²ã£ã¦ãããã¨ã§throwæã«graceful shutdownãè¡ããã supervised { // forkUserã¯è¦ããã«goããã®ä¸ã¯å¥ã®ãã©ã¼ã¯(Oxç¨èªã軽éã¹ã¬ãã)ã§å®è¡ãããã // supervisorã¯ãforkUserã§çæããããã©ã¼ã¯ããã¹ã¦å®äºããã¾ã§å¾ æ©ãã forkUser { // chan1ããã¡ãã»ã¼ã¸ãåãåºãã¦æ¶åãã¦ãããå¦çã«1ç§ãããã¨ããæ³å® chan1.foreach { s => sleep(1.second) println(s) } } // åæ§ã«å¥ã®ãã©ã¼ã¯ãèµ·åããããã¡ãã¯chan2ããStringãåãåãã大æåã«ãã¦å°åãã forkUser { chan2.map(_.toUpperCase).foreach { s => sleep(1.second) println(s) } } forkUser { // chan1ã¨chan2ã®ãã¡ãå ã«åãä»ããã»ãã«æååãéã select(chan1.sendClause("Hello"), chan2.sendClause("Hello")) // 0.5ç§å¾ 㤠sleep(0.5.second) // ãã®æç¹ã§å ã«åä¿¡ãããã£ã³ãã«ã¯ã¾ã ãããã¯ãã¦ããã // å度æååãéãã¨ã空ãã¦ããã»ãã«éããã select(chan1.sendClause("World"), chan2.sendClause("World")) sleep(0.5.second) // ãã£ã³ãã«ãå®äºããã¦éãã chan1.done() chan2.done() } }
ãããå®è¡ããã¨ä»¥ä¸ã®ããã«åºåããã:
Hello WORLD
Oxã¯Project Loomã¨ããJava 17ã§ãã¬ãã¥ã¼å°å
¥ãããJava 21以éã§å°å
¥ããã軽éã¹ã¬ããæ©æ§ãåå°ã¨ãã¦çµã¿ç«ã¦ããã¦ãããããGoroutineåæ§ã«ã大éã«forkUser
ãä½æãã¦ãããã©ã¼ãã³ã¹ä¸ã®ææãåãã«ãããªã£ã¦ããããããã©ãã©ãä½ã£ã¦ãã ããã¨ããæãã
ãã®è¨è¨ä¸ã®æ±ºå®ã«ãããOxã¯Scala 3 + JDK 21以ä¸ã®ç°å¢ã§ã®ã¿åä½ããã
Oxã®ä½ãè¯ãã
Oxã¯è»½ãæ¸ãå³ãªããããéåæå¦çãæ¸ãããã«å¿ è¦ãªåºç¤é¨åãå ¨é¨æã£ã¦ããããã¨ãã°ãã£ã³ãã«ã使ãã¾ã§ããªãã·ãã¥ã¨ã¼ã·ã§ã³ã®ããã«ãããé«ç´ãªã¡ã½ãããç¨æããã¦ãã:
// å ¨ã¦ã®é¢æ°ãéåæã«å®è¡ããå ã«å®äºãããã®ã®å¤ãæ¡ç¨ãããã©ãããå®äºããæç¹ã§ä»ã®ãã©ã¼ã¯ã¯çµäºããã race( () => { sleep(1.second); println("Hello") }, () => { sleep(2.second); println("World") }, )() // => Hello // å ¨ã¦ã®é¢æ°ãéåæã«å®è¡ããå ¨ã¦ãæãã¾ã§å¾ æ©ããã par( () => { println("Starting first fiber") sleep(1.second) println("First done") 42 }, () => { println("Starting second fiber") sleep(2.second) println("Second done") 666 }, ) => (42, 666)
ä»ã®ã©ã¤ãã©ãªã ã¨å°éçãªç¥èãäºåã«éåãªæºåãå¿ è¦ã«ãªããã¨ãå¤ãã®ã ããOxã¯åè¦ã§ãã»ã¼æ£ããæ¸ããã¨ãã§ããã
åç´ã«éåæã«å®è¡ããã ãã§ãªããexponential backoffä»ããªãã©ã¤æ©æ§ããã©ã¼ã¯ã®äºå¾ãã£ã³ã»ã«ãªã©ã®ä»çµã¿ãæåããç¨æããã¦ãããããæä½ãããªããã°ãªããªãç®æãå°ãªãã¦ãããããã«ãããã¡ãã£ã¨ããéåæå¦çãããã£ã³ãã«ãé§ä½¿ããéåæå¦çã¾ã§ã½ããªãããªãæè»æ§ãæã«ãã¦ããããã¤ã©ã¼ãã¬ã¼ãå°çãã人éã解æ¾ãã¦ããããã
// ã¿ã¤ã ã¢ã¦ãæ©æ§ def controlingTimeout = def computation = { println("starting heavy computation") sleep(2.second) println("heavy computation done") 42 } // 1ç§ã¾ã§å¾ ã¤ãè¶ ããã¨ä¾å¤ãçºåºãããTryã«ãã£ããããã¦Failureã«ãªã val result = Try(timeout(1.second)(computation)) println(result)
// ãªãã©ã¤æ©æ§ def retryingExecution = def randomlyFail = { if (math.random() < 0.8) { println("Failed") throw new RuntimeException("boom!") } println("Succeeded") 42 } // exponential backoffããªãããªãã©ã¤ãããã¸ãã¿ã¼æ©æ§å®å Try( ox.retry.retry( RetryPolicy.backoff( maxRetries = 10, initialDelay = 100.millis, maxDelay = 1.second, jitter = Jitter.Equal, ), )(randomlyFail), )
// 4並åã¹ããªã¼ã å¦ç def transformation = supervised { Source .iterate(0)(_ + 1) // natural number .filter(_ % 2 == 0) // even number .mapParUnordered(4) { n => sleep((Math.random * 100).millis) n + 1 // add 1 } .take(100) .foreach(n => println(n.toString)) }
ã¾ãããã¡ããScalaã®åã·ã¹ãã ã®ä¸ã«è¼ã£ã¦ããã®ã§ãã¸ã§ããªã¯ã¹ãåã¯ã©ã¹ãªã©ãå½ç¶æ±ããã®ãå¬ããã¨ãããããã°ã£ã¦çµäºãå¾ æ©ããå¦çãææ¸ããããããªãã©ã¤æ©æ§ãæã§å®è£ ããªãã¦ãããã
Oxã使ãããã«å¿ è¦ãªãã®
åè¿°ããããã«ãOxã¯JDK 21ã§åãè¾¼ã¾ããLoomã¨ãã軽éã¹ã¬ããæ©æ§ã®ä¸ã«çµã¿ç«ã¦ãããã©ã¤ãã©ãªã ããããã£ã¦ä»ã®ã¨ããScala.jsããã¤ãã£ããã¤ããªã¸ã®ã³ã³ãã¤ã«ã¯æ³å®ããã¦ããªã(ç¨éä¸ãç¬æã«èµ·åãã¦ã»ããã¦ã¼ã¹ã±ã¼ã¹ã¯ãã¾ããªãã ããããåé¡ãªãã¯ãã )ããããã£ã¦JDK 21以ä¸ã®å®è¡ç°å¢ãå¿ è¦ã ã
ã©ã¤ãã©ãªä¾åæ§ã¨ãã¦ã¯1ã¤è¿½å ããã ãã§ãã:
// build.sbt // ... libraryDependencies ++= Seq( "com.softwaremill.ox" %% "core" % "0.0.25" ),
Oxã®æ³¨æç¹
Oxã¯ã¾ã é常ã«è¥ãã©ã¤ãã©ãªã ãæå¾ã®ãªãªã¼ã¹ã ã£ã¦ããã8æ¥åã ããã©ãã©ãæ©è½ã追å ãããããbreaking changesãèµ·ãã£ã¦ããããããã£ã¦ä»ãããããã¯ã·ã§ã³ç°å¢ã«çµè¾¼ããã¨ã¯ããããã§ããªãç¶æ³ã«ãããã ãScalaã«Goroutineã©ã¤ã¯ãªæ©æ§ãæã¡è¾¼ã¾ãããã¨ã¯ç¦é³ã«éããªããScalaã®ä¸çã§ã¯ä¼çµ±çã«ã¹ã¬ãããã¹ã¬ãããã¼ã«ä¸ã«ä½ãããã·ã¹ãã ã§ãããããã¦ãããOxã¯ç´æ¥ã¹ã¬ãããæ±ãã¡ã³ã¿ã«ã¢ãã«ãé©ããªãå±é¢ã§ãã¨ã¦ãè¯ãDXãããã°ã©ãã«æä¾ããã¨æãã大éã®ãã¼ã¿ãæµãè¾¼ããããå¦çã§ãJVMã®JITå¦çã®å©ããåãã¦é«éã«è¤éãªéåæå¦çãè¡ããã¨æ³åãã¦ã¿ã¦ã»ããï¼ééããªãé¢ç½ããã®ã«ãªãã¨æããããããã¦è¨äºã«ãã¦ç´¹ä»ãããã¨ã«ããã¨ããããã
ææ
åè¿°ããéããScalaã§ããã¾ã§éåæå¦çãæ±ãããã«å¿ è¦ãªã®ã¯ã¹ã¬ããã ã£ãã軽éã¹ã¬ãããæ±ãããå ´åã¯ãããªãã®å¦ç¿ã³ã¹ããæ¯æã£ã¦Cats Effectãªã©ã®éåæã©ã¤ãã©ãªã使ãããªãå¿ è¦ããã£ãããã©ã³ã¿ã¤ã ã®ç¥èãç¸å¿ã«å¿ è¦ã¨ããããã¡ãã£ã¨ããç¨éã§ã¯ã¨ãã¦ãããã¯è¨±å®¹ã§ããªããã¨ã«ãããå¹ççãªéåæå¦çã¯ã¯æã«ä½ããã¤ã ã£ãã
Oxã¯ç´ç²é¢æ°åããã°ã©ãã³ã°ã®å士å·ãæã£ã¦ããªã人éã«ããå¹ççã§çç£çãªéåæå¦çã®ããã®éæ¸ãéãã¦ããããããã¾ã§ã¯Goroutineããã®å°å£²ç¹è¨±ãæã£ã¦ããããOxã«ãã£ã¦Scalaã«ãåæ§ã®ãã©ãã¤ã ãããããããã®ã ãä»ãå·»ãè¿ãã®æã§ãã
ã¡ãã£ã¨ã³ã¼ããæ¸ãã¦éãã§ã¿ã¦ã»ãããCats Effectããã£ãã©ãã¯ãªããããã¤ã¯ã¹ã¼ãã¼ã«ã110ã ã