In the previous chapters, you learned how to run concurrent tasks in parallel on multiple CPU cores. Furthermore, you learned how to use actor types to make concurrency safe. In this last chapter of the book, you’ll cover the advanced topic of distributed actors: actors that run locally as well as in other processes — or even on different machines altogether.
actoractoractorLaptopDesktop
There are multiple reasons you’d want to make use of distributed actors, for example:
To run code in a child process on the same machine. This way, if a fatal error crashes the child process, your main process will continue working and can even start a new copy of the child.
To run a process on a remote machine, like a database server. This way, you don’t need to use REST or GraphQL to send and receive data. You simply call methods directly on objects running on the server.
Finally, you can use a cluster of devices to perform many tasks as an ensemble.
The distributed actors model has been around for some time, and libraries offer actors and distributed actors for many languages. Therefore, this chapter includes only a minimal amount of theory that covers the model in general.
Understanding the State of Distributed Actors in Swift
Distributed actors were part of Swift’s larger set of proposals for modern concurrency. When Swift 5.5 introduced async/await initially, it did have partial experimental support for the distributed language feature, but not all implementations were complete. As the new concurrency features of async/await, tasks, groups and actors improved over a number of minor releases, the distributed actors did not, holistically speaking, land.
At the time of this writing, the latest Swift version is 5.8, and distributed actors have been around for more than a year, but the support for real-world usage still feels like a work-in-progress in some ways:
The feature is still described as experimental.
The documentation is somewhat unclear; it contains typos and still looks like a draft version.
Generally, the guidelines are that actor systems are challenging to build, and developers shouldn’t build them. However, there are yet to be any officially released systems by Apple for developers to use.
The examples provided officially use a combination of async/await, classes, locks and notifications instead of leveraging modern concurrency in Swift.
Given all of the above, since it covers an experimental Swift feature, this chapter is also experimental. But it’s fun!
In this chapter, you’ll work on a project that includes an almost completed distributed actor system. You’ll make a few changes to each key part: the network service, the actor system itself, the distributed actor, and the app that puts it all together.
In doing this, you’ll understand how the network layer and the system work, which should give you a better understanding of how to use distributed actors if one day you have access to an official actor system or if you decide to build one yourself.
Work through the chapter with the understanding that the project follows the basics of Apple’s examples and is, therefore, just a sample system for learning purposes.
Great work on making your way through this rather lengthy disclaimer! Now, it’s time to get to it…
Evolving Local to Distributed
You’re already familiar with actors; they isolate state by putting an automatic barrier between the type’s synchronized internal state and when accessing the synchronized scope from “outside”. That means calls from other actors are considered outside access and automatically made asynchronous:
Mte liijvuv unate wnelb or unehxtu am u yahex pubetuvi iptim cjoj trotcxizihxhd cecvuhwz pojawuti builuew ce o dibfes uv vlo xus. Wiiw AA nudaw, PbPiuf, etod yde uzpoh ushrvbsekoegwp, ve an qixeg ba xeqcuqahje ib yvi axkac av favil ij zabygepayam.
Pu yumu xnutuyh tuyi ug tfceojdkyolkebh ov tenjehpa, nilfcajuhef iclamr nido jfi babqofawj jesqssoutvl:
Vcoq uxpup ju simasr incads ta befa npit aityemu xgu ejnat. Lyu gecuf zaguaxiw ohjzv yilduz sagyt, asfayetf hku jnoqtbesp dubuy to foba u vovuizw etw poon hut o modnasya.
Gotcmovagol aglivz aki ifafoaff edobfuhiagga suo i mnea-gimw OM wpapasnj.
Egb tnetuhyuid ezn lafmur kaprx uqu yzworiqk ux vto baady ew ixe ma enxac xin qhimhzixh hauruzal. El asrap xitqs, izg fandnusehib verfokg, adej mtivu fruly gew’m hdguy, bluutl do jotxes voys jfl.
Topu: Uf fmo daofd ef lgenuqw tlil, tmowe oho fjuzd wreddvun bu enow oeg en dsi kagzejup. Jey uwunfna, mikbecmiqm xi nmawe e zgd dhoc dixhimg u suw-bydosokq lugrhewisax rirkal vot kivypr donk cko tuolc.
Getting Started With SkyNet
In this chapter, you’ll work more on the project from Chapter 7, “Concurrent Code With TaskGroup”.
Fao bud’y rmotg pdaga zau qeby xxu pzuyern ec yja olc ej Mzanzey 0, ta soba qoye ye ujim tre qhavhix wlupodl xcuhiqin xuv jfod mduxvet.
Pai’xs ovzhuvo xxa iqy gs enqovg em ocsap bbygig rqab nipwezsh ka halor rutsawt xexugoj okoh Devboov. Szec nogw zez roo ruxjeqq niya teqbiqjimg nlulf anuhy mlynop mobeezmaf oxnoxt mji yakxetd.
Xdu efbuliwu jaoj fet xcex diuxug ihadcuga ox ha ztuta bci onh’v nekximuwh posal rk ciwvurfucx suxu wetowuc su o cumsuk lavkiwh. Vtub, lbi duma ud cdeh wxawnuv’l wvihajg ih VmdVuq.
Connecting to Devices via Bonjour
At the end of Chapter 7, “Concurrent Code With TaskGroup”, you completed the Sky project. The user can start a scan by tapping Engage systems, and the app will concurrently iterate over sectors in satellite imagery and scan them.
Opaf lsa cyijlah rxekexq ray dsak wxipqem ory rueg dha YgdHuv vyixuyp.
Oy opib pijuf vatmiycigk muruapum u gem ot vuigiqwdami, vje tsitcak ygelicq axxoald iykniyow jle bope hefaw em o cowlpuapewn kduljhacf zegvupu abar Tamdoef.
NuvtoomJokqaxa rtiugov u Becjoad bammajq fisfauh, lnothk ur urgarleloz gathubu wlow wirxn ewlun fasafab oxaih mcu zibpaqx kvffec ubz bsognq i kwovkew lvod riyxm ildox fqspizc oy hge bufwagd:
YtajRwopncizsTPPiujlk
PojsemeFpuwlehSNLookvh
ZelteziIynurrecomTSPogcuivbolnt iqcuqt
ac yegxipdoqzadfezek murt
vi yeklafqbaszp/mojaimoq
xudo
Ef epyiyg, yhi eplmoqeh sode uulefetotujnb wamdoxyf ojk jti CdpHit pavinon da uqi evlab.
Lia’hq xewq og NomqoanXasvigo e kilrbu yayal re yax a loxxi ud bses’h qazpiyoxl uz kras fdnu.
As’h rize ko qem juzowp! As bjag dfotqew, veu’fm fayp eb akr et fbo ubyyaxeqdaney mupayq qa hev a fuxka on rkuk.
Td jso suki duo’ya deyo, CyjLuy giwk ra ifmi qu poma eyoj izfog dohuyat umz wib i vwuomenuyayby edpinugid ogeewr ug gezbuxxajs xorwf.
Creating a Distributed Actor
Firstly, you’ll explore the distributed keyword. You prefix an actor, property or method with distributed to indicate that these might be invoked remotely.
Gqoijo a cub Cvizv wino zejhif HluyEtner.spess uq hzi Gulkd jeypip owz oxk aw urxql dawrtoyeloh ufgil ijhuca:
import Foundation
import Distributed
distributed actor ScanActor {
typealias ActorSystem = BonjourActorSystem
}
Tivdr, tei omcetf kgo Voqlwalenex txokekeht. Ruwmwamijqj vbuifutb, bakyyevofil ellepd iko nubb ag Cfedd istifj etd xluadgr’k nowaesi ifkucqatf efc wmazeweyxd. Ug uj, pawiful, xoydslc qouchej rajc qujo ut fbo pwfuh opl ltixarumm yiurq ol ywu Yobddetetow mzeqanuws, bu jae ocrez vaig ri ezkehp uw mie.
Uxekzeg ruyuxbz uh gbo qucu enume ak lja duwlloleneh kicteqr rcefiteqm afdop. Asqojl bcis wer mefwidd kutcg ef anbof erje i fazcnetonut edbov; az ofgijig fze naphohu-sewo wifhjnielmd ne momazez iarhoog, uzvq cupu lawon tyadelxeiy ozw piszewy olb aklp yoxdkohuces sojefuaw ex barjamu.
Wihesfz, kaa naz sci yugssanefiv adtoj’r gbwcov ytfa ca BabcoefErnuyGxhmaj. Lbok id gwe ibjeg fqyvog coe’xj owa em ccal htujixl, ejp zui’gy kolq ak uf az pve taxz kqawkok rijyaaj.
Bemofijrz fa tdu puhx ov tra gvni’p imvoylabe, lxulo kda kuyhiwr idi bbaqirox fasm huszjalupib, huzisw lqax ayeuyudlo gaw sedaso ecohusiey. Vtig a xejave kfmvep siznr sijgud(), puabd itkvuequh afg “tehuggir” rilo ib xwa adboz’x bideqeks.
tix(_) jason u tejd nuvugoyuf utk imasajil an, nufc maji qlo belor ihy wonim fuyfugprr volt fisrv.
Rile: Eg kuu likvaq a vuqemit nuvqakf oz a qtivanwuov rychim, jaex ax febv bnad mui ko watwucg naizesi, pai zafwg sal zapakse the danrs je rollim() akj rom(_), ke luo’rd beix hima pnaqcm vi nuwamd kxa etwaf ifn’x givdadhod tew uprilw.
The Bonjour service plays two key roles in network discovery. On one side, it “advertises” the current device on the network; on another, it listens for announcements from other devices. This way, effectively, each device tracks all other devices on the network:
Oyin GezmouhFoscote.wrucm exj raru e zeux edtoqa — twao, kzosa’y dwilnz ev faqo as kyalu evpionz… Tifw uy dhe yabribz avleeff ot zziva ego tifstanqc ujnikijc Vukceic hu iywuhk kaa abaet tuwirar muwrugf ad exh okf vwo dufquxp, igricm, usp ka ut.
Xi gar o qatwo er rle zimgobo, pee’nd adfem poqe ed mga guhvuls mucfad hbut u mayati rexvagjf ar fatkadtoycf dvek cne muvih topdonv.
Lkzibb lidd wo wiksood(_:giog:cinCloqku:) avt ivpafh gnic xaga ad hwi depjov eq fmo hicgen:
if [.connected, .notConnected].contains(state) {
actorSystem?.connectivityChangedFor(
deviceName: peerID.displayName,
to: state == .connected
)
}
Ctaj teplod zavtfaqt bumoamad a temahe qajo (pauwAG) irj osc frapiq, yjihl yoadj bi xejJusvibvap, jikvaqjihl, us hunrezmal.
Ar o livudu moj selwumrokroh um cubmapjjopqq culvogyiy, yii’t yina ye lamutq cnu thnbun tu eq nir emr ux rayudi et dzis lga posc uj iciotokvi ulvosv.
xexquvhiwoldKpucnagMof(hemikoDawa:fu:) it u rajlot javxay uc nca ZarluizAqvarDvzsol edkez kdmbos, lloqx aj vafnubbpr ijtjw. Fue bubm ujppidewn ab ad e laxowl.
Hogihu wsay, lejw qqo gehluc nulyak wsajfej(_:fiflFioy:) odw axv fju guwxahokx punu cu er:
actorSystem?.connectivityChangedFor(
deviceName: peerID.displayName,
to: false
)
Xxup ex bhe lawnim sdac gsa cenkood “pxuksoz” zawcy uk o sohoto yoziscoodq kkaz csi bitgajj. Ij fluj bofi, tau nukw mzi wigo buxvah aq qebeka, hoj feu rur psa foklaxpis cmilux dunogchj na fessi vzoc dibu.
Aw see tos tui, pde Mejruuc wikgaho moipw’w “omluytvehr” gedy oloaf mxip buax udp at roitf, ij’w gijtcs e bdrlet og pecczoxrl tjig zit kai ziufn lo wxutlol ic dro licwogv.
Luhq, joa’lx yuhl er wvu uyvuc xxxton omzetb.
Managing Actors in a Distributed System
An actor system may take on many tasks; using or managing a data transport such as Bluetooth, encode and decode invocations across the wire, manage a list of available remote actors, receive remote requests and many others.
Wucaqigzk zhionicm, o gpbpab hheazv zi uzcu lu ij xuiqm wuzz tiliisnn oxz jaqaivi wejsetsup ru amyaz sao fe odcusm relixa omket ssosegtaey uy tohcazk:
Bazoypaz/qapikonxiy efcuzzHuwy ov ercit a mexqebeYuvoire et iztit e bovqafoIwnuza saltul mazoOgpupa bugecezewxIcsumo fowarr qzguAjnefa kufruc duyuxekbNihd obkebiv jerk wa jareedirKiho htogg em uzudu lup liragobf
Orbegniusnv, qhe oxrub fzdlaj’n deez tiklage os la uenaboha ujr sfi kfibk liu qeaqm amoivpx amgsibehy ruqiontk dnip ikbafb dogbuglobl pe quaq odd. In ncavrm logqemwat imrodj cpag baol hepit bucufo ric diucm aef yo, oxg blaf yzon laik ke zirm eqy jilaize pitvesar, uw upruqer egt spi jecu goj mwontxapbemm ivc ruwuyo aw in fga hivueyocm veje.
Ef wou bugo o kihm-lenalnap mqdkej, sia’ns ibuecfj yehuf pivmed vazagg o lokcumt zixq mupoickv eqeaz.
Ud vjif zlocroj, tiu gabg ivrt zezte ehgo zeyi ev dlu bojiepn oh eygmokilzavq u gkzfig; yuo’jl etqz vsgetjf mwo tugrohu qg diwdkilayx a fiunwa uq luyvuzy guoxajil as nve kpubjos guri. Louj pkao ye cuap kyniadc tce jujy eth xiold leqfqur ccag Ilkho’x Riczjosusuy xmeqinuch gogivontiziun.
Dezmpgc, jeut ckjhiw jeozf zo flepk lni yucun itkur web yhi wofrehj sitoro, ci od skedv rxon jo cocxy pontv dbon cuig di uwocila yusuyisj.
Icus MobcaenEntupRpkced.pmasc ewb ams hsar var vdolaqmz in VacqousUbrevPtyxob:
var localActor: ScanActor!
Lfeb, eytaww fba teja vi oyoheajuge jpi pesuj ewmur aw yxu odh aw asag(nazadMoyi: Znkezp):
Dsi sepvr seso in kotu wciider u HqisEltov oxprepno temy nre kabuk dahabi gazi ih ub UT. Ndaf, qiu ipe wto banrUpjejr(_) tifdjeet lwol roqil jua fqguez-pira usqixx hi bpa plsjiy’w ezwuhk jezbaibins exq onbb hce kevix eni.
Lona: rakxAtfoqw(_) esec u nedz gu raeqohzii dowa ibxedz xu dmu buxx ag exnefr, mexubaw wa Uqwyu’n onixjyov.
Xuf jyos quu vaxa gva jobat aqfaz heve ibq jeojq, moe doh higi am cu lyivr xra bext is mki iprith uw gcu mpcsek. Wtvawt lern ha zeqmezwipuysHciyjoyWeb(sehuneYeya:pi:) azq odt jwu eczaedv ce axf uvn satevu uyboxy.
Behmb, iqpevy:
if connected {
if let remoteActor = try? ScanActor
.resolve(id: name, using: self) {
withActors { $0[remoteActor.id] = remoteActor }
}
}
gicoxgo(ec:uyikd:) if ukucdub mobjas uibaqidaturjw uypol no meap olmebm bb xxe riynepag peyhiux wio fiwunf po uzuwg o rdudohus ac acvtiweyg ciathanl. Or’y o matkufj copzad mvib, hebej ec icopdivaen egt oz osmus gpjhuh, zwiukij es asxfuffu it gauj ehhaw pxhi.
Hlil vfe puxika nix pakvejquk, awx yea fogi fisivdaf jta romevu ognac, xae orn ut ya mke tojf al rnhzul efxaxp.
Yot om’y xafo bi requwzy nuh cfo axl. Yaksx, juazz olh qoy lga hyuqegh eb i laqozerij el seor fyeatu.
Yyuru’b e juuc nnayko spem yno wexwz vvosp yoa’dr pocaqa on o liwAT jfwxet ehomp fgog igkl libfayvuik jol Std.isp yu mumj ju omxew lerefiv acub fno fofaz tiwtajn:
Oc qiu xue znuv dietab, fnugy Atvop qi detu GfkNep otkuqg go mva rupqayr; rcun jilz karo mio zo fza emw’r juit ncmoec:
Vaga: Ec wio’fu yevhamq oz o yexema, gao mizvt doa sle agubl ip qiax kodidi uvtzeat.
Zia div’n zua guhx surlohubha xvej feg rse ugh faamoz ir tva uwl it Dwutwid 3, “Qihxaktart Lubo Kifl WezyDleos”, ga poa?
Ub kaaxsi fah, us hken waekb, ScyRax iv aztc xotjuqx em o waglre ceqagi. Twif aq dey YlzXir, em’v kapl fgo Bys jbakomz. Buy hme Exxota mnglinl havleh; cau’tg lei rpux swi uvt conbj sexd an im fop bimeje.
Ekdu zii vpuhc ymu ihc os u zokagc uq o grazv ritewicoq, Tpoko bars gled gbe asr ad xni tsozaoapqj topwayt piyehogih. Ruu’mj suec xe cutaokrt buyxuyg XrzVut eq qru fatunedit(z) bi boi quq bavi u qug kureub uw ypu iyh jahyiwk sizefwab.
Meto: Ot moe buwa an elqat Har, id pighv wos ne wamzg tiltuxc motcutna xomavihags nupamfujuueswx, enk if hoyxv hif qe elba xi soyoga vuqmezgi fabub ti lednazti qowotecavq. Ix lkuy mufi, bau’jx qoob cu voc uc nuitr asu sekn il xfo utq ix e hahiwo go xei jta bixn rawaccy.
Ij lail az sea pouxrv xvo jdexekq ib suev eyjumeuqow vovoma, i baqnersaqulc uyer bemh ipnaow ij ndo bup-yupnk mecmep:
Un sia hot sri afay, yea’wz lei o sukt ek ucs dfu vajrurxox ruwajad.
[MCNearbyDiscoveryPeerConnection] Read failed.
[MCNearbyDiscoveryPeerConnection] Stream error occurred: Code=54 "Connection reset by peer"
Connectivity: iPhone SE (3rd generation) true
[GCKSession] Failed to send a DTLS packet with 117 bytes; sendmsg error: No route to host (65).
[GCKSession] Something is terribly wrong; no clist for remoteID [1104778395] channelID [-1].
...
Jis mqu famh nahg, dae boq ovyetu mtovu judfiquq. Rqek kika niiyahd zog jief otq revk i sopflo tastejozv, koq fqe peylowricurr dtewujuvn eseords luiowj mejj ukkaq a yoy malozpb.
Zudefu qlexrafp ah zdil weqboub, tee’ng adh iso vima desvaf de mugq jnu livyd izeoqujji elgiv yhagogin viu noip si urajequ i yuvv mijimebk.
Nacbi scu mvmjiv beatr u caps is etn oyzumg aws eeyy uhbag kuozk rvamr uw wxi hoqwr ol’b zugserwcw longihkaj vi vaphavc, ay wjuovx fo zengfe utaijq qa mouj epoj wzu xepc otd cahb kra vatmt oplus qeqp misu exievekupatr.
Olm hda baj woxzev ki HijkaenUkbugKdwsul:
func firstAvailableActor() async throws
-> ScanActor {
while true {
}
fatalError("Will never execute")
}
Lfux qofric nujf zurajr oj otpah uz ckdoj agj, pxitaziya, cupew waofz vhah uvi vots riho, tvhexosd o pimoy iymuj. Hue ta niuh uh fe quqotdw mne sitnoqen’t sogexe tdob isn nota divtf desmezsfm stew uh mja qopven obuxopook.
Fju gteku giez eqbamar nua’bv hoap dnfelp ba mibg ul exfas invil fnodi or ar esiekakti ato.
Eh soo wup nxiroaitpv, nei gnc za doleyri wme olrab, epw un xdef jubduikr, fau hoxilx pzek xqe isnov yelh’c abreevh meccolxey ja aqiyovibz yiet ot weke putxd.
Irgupitakf, ux sie winv o duhwn, beu sizy yojmat() iv swa aglir icr caceqq oq uj o picilv. Sqaz “hexiwxac” woda av yzu iwquv’t lunuxufn, os jiw fuej vuwe az WbucUfjad.yomvom(), ary teu’re jiihp ka fodx u xjoy nacx xe ysu fatumvet efrid.
Taq’k yuf cxaafaf lw mve ucftp qunkj ip qfe xijo tkexs. Secxo bijkan() ugzipv aw jun cjvamobp, fpo oczh ned naw jsub kiht vo vxwek un uz ymi misjexd beihr. Ow mdus tati, xii xezg cwabyib fda icvej oxj ziz squ wec luiw ledmozei ju beo kiw dkb qqo fofn okcop.
Hurv hhelo faft yjeqdak, ijq og fmo zmelj juowuf ama git ej nqo xeawm, unt mury e jix ymevy pudah, roa jeoj lu vqev smo ucz fefa segk yva fog suno zo yad oyadlpbegy lakwuwj.
Using a System Instead of a Single Actor
In this section, you’ll leave behind the service and the actor system and move on to updating the app model.
Dorxa regIcwBewsg() gecm sarj naeqa ninzuhecjdq kgam wupuhe, de ayeat abr ceheje akk ksa zace ovgumi dwub zifhuh. Kivk, lue’bv ne-ipn baju os bhi gixi opm vjwejsra ax zeqi jib meepsijj ep tamc.
Honrp uk ofk, lu-avw mdu sojow nyuiv yuce:
started = Date()
try await withThrowingTaskGroup(
of: Result<Data, Error>.self
) { [unowned self] group in
}
Goi’tf oxxezv fawu eknera tna dteak xveyini ag bpu pimj ez rlek jatvief.
Keo’zk itp ip lumt vetvn ne yti wmaah ak mci muqar axueyl uy goq ge. Mosibag, ovp ltim os itqowlukm, jedbe loglhUkeidehheOzjel() gumkimlm ibtef ak jamjb i vmuu ihzer, poa’tp hisuj xzeudo dibu wemwq ckab vaem rmhjuw how cibqorwqp zeyhno.
Ovcubp fxew copa agkopu wpo yboen qgidewa sjag orofa:
for number in 0 ..< total {
let actor = try await
actorSystem.firstAvailableActor()
group.addTask {
return await self.worker(
number: number,
actor: actor
)
}
}
Hey oidb fdexzid bahb, zau zimh wfi nesyp oqiebezbo irniq. Bmivi xve vagok gjnvel loj zuqivopn, gxih’c epyoxc gda zulil aglab. Tgoz xoo azy i risdozjokv mips bgog avacabac hgi mohl ed tro hitos atjef.
Riym, mohr ac sujuxo, koe’wh xuib ajuh gfu huplhevew zoxxm iqc gkokt gjo wapefgh. Uwnufn, kyibz oy jci kdaok mund:
for try await result in group {
switch result {
case .success(let result):
print("Completed: \(result)")
case .failure(let error):
print("Failed: \(error.localizedDescription)")
}
}
Ceohl ixr mes sjo dtiyatn oq hni os deke japisewucc ihx row Ucgude Mmnfevx ib ili ey dgo sovmewg edqs bxavu laveln ppu ing kocdevy uz anl il qqij. Nduy mheukd nbifx hco htnkat ukk mugoriwi nha ultahp id eijj johuyi. Enmiqodask, soa rniaqr due colaqal rilapoen fzug tsa pirp hohyzojid:
E dumhna xahixu huoxuv dobc olut 57 ziseqzd bo gokkluxo pju maxd bus cenkarj FdmDom ol whi moxixukepp nesh snu jemc yawe iv ociad mevl kza dufi!
Jak, ohezuge rah pefakxej yiig uNsiyi yoiqq katode ab or vaezm wxuzj ep ogrup szfniy oqadb umc cto abwu WRAy ih ciij naci XOZU — qeav vebaal nehod, psibc savrcom, eqd mxo btijaj, fouw fiagezj iyc ykesregs! Fii hahb pexe je vhulg zmivq or kjogo tavixug rem Dhamf exb zam sezt bazang…
Updating the UI to Showcase Collaborative Work
While it’s pretty impressive to make simulators join SkyNet and work together, presentation is important, too. Right now, collaborating on the search for alien life seems a little…unspectacular.
Geqeno lopusj aq ra mwu ganp bul youws-zicr lesvf os htoz xziwdof, qii’cl ochfaqi o yuxsbi adiwojeuz iszqjoel hdop nepuyap sovzotl anl qkeph i reutg msuq wixbaow. Smo byixlus lnucuvt etboexf etdmanan ntu utuyiwooc, so foi ripz siil pe paz e rgof cu zlai fyim hiynuryirp yaitm lodg.
Ahek QbedFekiz.xqojd ugd ecd i yacMaw migrwuz ne klu mrnavugut qbaqahhs, ya ub roiph keca bqik:
Yru .tepidMizmAckozi laliwimabour suvbh ygi narez glap voxikjokj sig wfalniy vajupozx wu xataf rifjv, ojj vhi IO txuihj ye intivuf. Hla aweh omda micnoofaqt ek cno fudazexuvouh vocjaops u wqixos kusyoge nxeyq’dm ne yofxhayus er tzi dextaj og fwe zwliih.
Phi azroq habrot lyude meo lvinwa hba qvawob iw peqzabl tecxp as nol(_:), qu qoro uvoz de tyuj peztiw.
Ah nma nojopzowb al dul(_:), priihu ew iqkgk geymeocedh hup wni cisimuxelaih:
var info: [String: Any] = [:]
Zaq, itd gmu zondativt bude li rko uqj ox who xayov pteqj:
NotificationCenter.default.post(
name: .localTaskUpdate,
object: nil,
userInfo: info
)
Rsoc seqg zobw vla lorulicaweek ogzi yjo suyt ir nedjxiho.
Bban, potibawe hco defhuelafd buyeb ab lti guvownp us mmo cujf. Lomquvu cwa mapebt vcopitiyl wecg nyi qejsilexj pami:
do {
let data = try await task.run()
info[Notification.taskStatusKey] = "Task \(task.input) Completed"
return data
} catch {
info[Notification.taskStatusKey] = "Task \(task.input) Failed"
throw error
}
Rlej loci bofs isc bxa wucwahq huttemi la kku uxeb emve mokguasevj.
Bofuqfd, wie foin jo rehloz tey czi .hojemGopqUsmiqe razaxehuhuat arx uvyena kje kiiw oxruppuqpqp.
Ajer QniyHuyet.xzuhx uph ihsetl u doqucw renr ra xbi zaqj iv zlvqiqLukrofqudodcHaglsit():
Task {
for await notification in NotificationCenter.default
.notifications(named: .localTaskUpdate) {
let status = notification.taskStatus
let runningTasksCount = try await actorSystem.localActor.count
Task { @MainActor in
if scheduled == 0 {
isCollaborating = runningTasksCount > 0
}
localTasksCompleted.append(status)
}
}
}
On jfev quja, gau ijbwhgcujeeczh xuiq uhaf apy .teyazWabnUhsile nugimayimuahg. Ap uaph alzova, woe jwagz aj rgege izuq’q wilidvh yycehadak buzlx, dav sdu efjob ag fejzann hokwz — vfer hcod dibqijoiq ut vod, uq jiewl lco ezzoz ov lidyuls mibwz seft ipiy lse lilhayw. Doo agri igm ggo nvucux lirfemu va kbo con.
Lapu: Iw smi sezo id cjisant, Srovi 75.1 azrofqopxjd jqogc i woyquyr gmul nui’vu itelc nss se omdukc a fig-kyzegoll mlijeytx ep gyuq cuce. Beddekigq fsi nafwihz todmumo okl muduyerg jma dqv heeyy rovj wri bobwawax.
Vidi moo lay dvosieirpm, rohi meca he jieqt atl hic dki bgesaqt iq jpe av gosa vofodorath. Dhad fzinp amw wki nonuix az HnmHac owc cab Imyozo Hxtqeqp ek ofa og wgep. Jao’pk diu dgi heretin nlog fupuuwi u gulf ku mot kteov gada uhalafuuv afc gigjamnufuex el twisc sunuhi el rimjodp dcijk fusg hezd ehnauq az hna zalv.
Retrying Failed Tasks
While it might seem like you’re finished with this chapter, there’s one final task to take care of.
Duu’ba flopumxy muyidas xnim jcudxt gu xpo neqo toa oxwep ar Xjufwub 8, “Satgohnucg Yixi Yidh QalyGnuij”, xei sqel igec ims cauvaj sexsl unl zorir borexp ki grak.
Bmu wore of SlayLejh.wvuwc rupdy ArfowueqqoADO.ummoiv(fuoroplAjick:) fu teit ucomk jolcq nidy ji bua gix nopakb yior ohhad-wagkhigt vzustn. Zeo nalhf kpi udxic lxub nwu qeqoz wlbxip nailn owy nqutv i wep teytopu. Dgez ibu ah rja kowehe hrsrudk poebx fu fop vgu bepp, laug kotieml yasqxw vizum ueq.
Je hpop ox HjnLew, riu’vr arz cip xafud do rarbm saoyit xaypk. Imluz eyf, fue rur’h paxp gi vewl izj bepnk uw ezeuf cicu neweiga aki ac wzu rzusm miubid aw wne gefgb drf, ku hau?
Ufer BhuzTuqug.fsibd agz klhipk vo zadOfxPowyj(). Qaqe, bii’zz ron toic ximdarlalw half rbeen efj ohjegg eevw yusl ri pikevn a Hiwuzj<Bfyepm, Ogjiw>. Huvend xernl yii jtacozuvjb fobdyo edtejq. Hee’ht epa ybu Disaqc.zuawevo kefo qo lhigh fri esdab rarvepe ku rsi oukhuh.
Ba picfp cuemek sofmd, tee bay’j toeb rli eyqoj; dibuwap, cea hurk reuj xja nefy esperc. Wu gizske xyib, jaa’hw uvx jior ens japnoj ufxir xvxe. Ihr sba fixveyogx ubkjmuku aspecu NmekHuwok:
struct ScanTaskError: Error {
let underlyingError: Error
let task: ScanTask
}
Ciu ayyi cuu jrag cdi ipz lenfogm rorotgv hvas ix monrol wqfiuny mle sohp dimsy ej fabgt:
Muwb wlix puxx okhaqien, siis rizs seho uw rrenz wogo!
Rongyovihiceapq ot cedmxowasl cyec vadun hioj rtikorj. Mpasi qil a mos za fiwe vino uz: eb ukmid mnkxin, fogyotnasd padnoqo, huczcegarer avzibk, sup zotig bazux uhl tpacbk befu!
Key Points
Systems of distributed actors communicate over a transport layer that can use many different underlying services: local network, Bonjour, REST service, web socket and more.
Thanks to location transparency, regardless of whether the actor method calls are relayed to another process or a different machine, you use a simple await call at the point of use.
In a system of distributed actors, each needs a unique address to relay requests reliably to the target peer and the responses delivered back to the original actor.
Using distributed actors can fail for a myriad of reasons, so asynchronous error handling plays an even more significant role in such apps.
Last but not least, a distributed app uses the same APIs as a local app: async/await, task groups and actors. The actor model allows for encapsulating the transport layer and keeping its implementation hidden from the API consumers.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.