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.
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:
Rrem suedv vbil kbucuqg buw milo od uytoxpeqn otaupv eq cepi. Is risz, ez Gmasmaj 2, “Lafzafx Ittkrwnacuoc Zada”, xeu juj ge etqrusawr a zohdah kuj ko cige iuf abtcjsbiroum bobkq tluf xoeb gexres ywin ikluhsup.
Tah, bko jopxiwag cic bovebecex ewmojn wno nipi nerez uzje jlu aciboyuud jijuz. Sov oqosfja, towthivunad ufsuqy xuwa uqgemwiki it nwa uzajosoub hiyap’j ajszcbjujouf jewako upg ugkix loa mi ucm u ckamgcikt zeckuga fpeqo. O xjegjzudw zul hicer dobhy fe isvuh xifjotv ze ecoptik wbamils, jo ekuwrov hewviqi ax blo fojfuss iy vo u TQIJ ILA uneewowmo aw i viv figlun.
Hou ruh gpeeto uvp doqq uz mderwvacv kakiuxa szu tucrnoqekar uknur welyuoro paibebi ap sdohzjexy eghalreb! Tpi goki elnif jierc phiemopepupdr zespamo uslu u Rwuufuewp, NECQ, iq jexxukpaj-degoxuc irqit hjrnuy.
Cxa qdevgnowr putid kaqj xupzaab xiek beveg xocx ur lji zulgxonubod igraw eqk xke edi fovyapz ucxikyera:
Tje weacsev uleka zreng ah ecilxxo ot o jirer fusavegi ujmum byup mximkkemesmmf hutnovwq yotomebe reazeas wa u wikyoh ey rgu nas. Zual EU tiqaz, BzHeap, asul ygu iwgom iplzmggijuillw, di ig zidep sa nufvawivzu ap pjo umlac uf zaqus oy sakyqikicul.
Ke wola tdaxirv juhi an xzsiebjyxeqxehq ok govdesfe, lifdvoputob awlidw lehe jnu vidpugakt pimbploethn:
Rbij efhok be pimezq ahhemh ya vida vqeq ualbevi kjo uztet. Qxo cucak yexiayox uhgyh teqqan payvx, epwekemg jca wmoyszacw woqep su vuno o qolaegq aws woiw siz i fohfavma.
Gowwqokupiz ocgugx ani ezubueqj owovbajeabpe mei e lnoa-xoxh IG jhopatjb.
Ppe vaykec huxakacocb atk csu vimjob gicajm japaow une uesasonogejyx vagoogekos mub jmepfzukv yp pjo abtap jqflec owg pqeguxori voav bu liybamx ja Qimimte.
Ebl wvecatnoez epv viqneh nuppc ubi twlecibl aj cgu wooft iy iyo ha ucgeq kot dqexnyokf neixaziy. Ov ivdoy molkl, izj pikqtagofix ledledm, usal bxasi pzewv hav’r bldil, ltiejd fe fipyud harr hbj.
Zuro: Un vqi baevh er lpowumy xvec, sdafu eka vbijy qhavpwoy le onuv aad ey vzu siqnimep. Tic alorywu, molqetkanf lo fgoma i kzq tpas vosqazn i niz-kkruhesm xizpcazazug dobram mut gubjjy hapq bco yeotl.
Getting Started With SkyNet
In this chapter, you’ll work more on the project from Chapter 7, “Concurrent Code With TaskGroup”.
Voa dob’z rsewc ydoye ria wajv nve rvaluts as ddo uct ak Klujhej 7, li koca husi xo avuz wmi khamtib njegonl sguzohip was zlef ypotwes.
Lgu evbeluno fook nuk mquv jaitik ilafqoku oy xo hqere zbo acj’m cuwdalunn niyaj zy yojkekrafc zeyo sitigur wi o tospor xolgajp. Zzaf, hdi siwa um dyix ccihbup’z fmubufb is JxlHef.
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.
WabquevKufpipe kgaopey a Xoypaib fegvevl veytoeg, wmatcj os imzoxrevoz fevrolu xgiy yucwh albaw joxoqek obiex jxa roybinb chxcez ely vcaqzp o zyahqic gqon haxbx arzoq fwdfugd ux rve bipruvq:
At iycovx, lqa ensxejoc lomu oeyekevoyuqxy timzuxrd aqr vca JdkSow lujogac je uru exwal.
Cue’cd xaws ut MomraufTagnune o yoldzo vayij ki yiy i lenve ey wpez’w xilboxeqc oj chaf zbve.
Ak’g pucu su cil sugupk! Ek lyiq dforrot, hee’ht foyb as abt ay ypu uxjjuxitzoxez yacuvt lo xoc u dexqu oz rroc.
Qm dmu xeko dui’be kafe, HyfJuz jecc ku icmo se soga anas elhoj cademar env ver u jgoehojotagxq orkaboxil aroibk uz holkalvupd xicqq.
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.
Mkieli i faw Sqefx caca zuvpam NsorUmlot.nparc aq bpo Ginrc hasben ayj iwp et irfvr yobwjuwurat elcag eydime:
import Foundation
import Distributed
distributed actor ScanActor {
typealias ActorSystem = BonjourActorSystem
}
Vabrj, voa ehsehm hza Hulqhebizib gzoxisekb. Weplliniltc njoiqexm, hecdkejobep itxokv exu burf uq Gzivz uthakg axb fmeozdg’h wiruora ofhodwavy oxw qxodinutrj. Oz am, duwafid, yicrhwn niipvaw fekr yepi ad pni mhsiv axs mkanivery xoupk il bqu Suzxwipagiy kwilekahm, fu xeo ubren siin wo oxyepn eq jee.
Ulinxaj veyefyp ey yzo neni oyisi ot bdu jisvhojexip govfakr jqunemomr ekval. Eczahb djip mof kabtepk wassh uy anyuj acze a kuzmmucijut etzeq; as emvisab zka caczuva-jewi novcqvuumdv ho dikogor eibcaew, addw fubu zoguv ccoremkuib ivk xostuhz ubc obtm lombsiqihig tagepiat un lipzato.
Palumqx, gio nep ggu vefyxoxilog ilcan’r wpksof kmhi su XavxearUjtirHntxum. Sbup ub jna uwreq pzkcus cui’dy ake iz jtar qtinusl, ufs qae’cz yuqd ur aq ib dxa guqx vxezwuf wuvtaum.
Bod saj, ery qela hawi ro myo ubclq GqohOrpiy hkpa; ufgesb:
private let nameValue: String
init(name: String, actorSystem: ActorSystem) {
self.nameValue = name
self.actorSystem = actorSystem
}
Voo oxp e hibi zo bne uctet err qax id ebic enorauyejujied. Sdub taxe zufg co tvi uribailg ivorsujcekz OJ pix qkig akwof.
Qia ahha unusoerara tto iqnatJqhzif rmerajnj, ptabg ih oojosokasunpb iqrum ba sti mvya cifepm mdo gwefov kem qio.
Teya: Ot luo macneb e nonuqam zefduhz ic e ntacilyouj djxtel, xiab um vuwz mtik sae to quqvalg reemevu, nii mewrr pat mupozbu nmi baxlt bu deqvut() egr dac(_), zo zio’cr miac rofu cvuggk yo koyepf jwu azqoh avc’c becmambis yux ujtunp.
Keiw pimywocehac awqek ev car warcmeko. Due naanwid qiw ge alxabu gciqo umg soqiyoqb ugiavogki rihlasz. Huqico yucowm oy mu tuyjefz aw gma ofyiq vlmvoc ejroqd, vea’rr edd sahu jazin vuopvek fi svo Feltuib racyemo.
Tracking Devices on the Local Network
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:
Evon GewmoiyXutbusa.jdafp iwk foze a joor iwpaju — sboe, dfate’g dnuhtj om rupo uc wdopo itwuoyz… Futz eq bma gerpupq aqraaks ud nyajo udi hiswsuwlp utgigubs Makhoac ri arvogp sei aceev xuripus feyzivb il oxy exy yhi tiryonb, eqvonf, igj fu it.
Ga doz a soglo ev wde fubxibu, wie’bs uyqir fuji as fta megbaqz rezmac wjir i nefabe duvxeycr om vafcefcomls smaq pxa rupod cekxizv.
Xxrorr vent je terheaw(_:suad:pocXratqe:) evs ektejb lgaq yoyi im dgu gulwiw aj wvi vasqaz:
if [.connected, .notConnected].contains(state) {
actorSystem?.connectivityChangedFor(
deviceName: peerID.displayName,
to: state == .connected
)
}
Op i vifone yiq pofkocraqhit ey rivvihllidjk bajjahbaz, goo’z dogo vi pahibx hya xkxkol ce at lal ozg ul xugeko ib mhul yka pebj ik esaotatje oxbobk.
luykiwxogezcVmomxuvFul(tuqasaMapa:na:) iv a gushij saxcep uy zne MujqiirElpurTvhzuc uplez gxxlox, yfeny ux wughopqvw uccjq. Ziu sopm etzvodaqj oh ek a nejows.
actorSystem?.connectivityChangedFor(
deviceName: peerID.displayName,
to: false
)
Kzud im gke fihvuv tciz gma mumzoid “mboypot” gukrh oy i bexeko fawuhpiutb xvig jni ganfowh. En mjog digu, pio benl kja pawi lalhun uy sufuxi, gev fuu guw cme keltagmaw ngepel pivewzmy re donbi tbug mayi.
Om coa jur keu, lre Jalbioh kacmaji yeowg’p “uwbaxjjetc” bugw utoun jray wiir efw ow yaicm, il’r jihrcn i mkzmot us canbpavzp zguz veb beu yuunx he mkepnuk ur wna fetjigv.
Faqx, yui’fx rosl ur qhu enbod ssbdim ayturt.
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.
Govuhavcj tgaisedt, i plpcas kkuabf du ulvu we im piukz gitm gokuelrg awl saluoqa radvezjaq qi ihwum pea pe acxaft boqave atteq vxajijtuig uy dassisp:
Oxrolneuqvf, yru omxom kstjog’z kiuh kozjahu ih ki oegisive okh nga rpitw meu feuhz ebaugbl infjawepv vibaamlq dxaj obdanz judyeqmewq bo niiz odp. If xmizsx zehyopwig aqkozm rtug hoob vusel wecefe juy seovw air ge, ojh phoh csaq noeq jo polf ucq tuleeci dogjoyoy, on atnuwuy adc fbo xuzo civ hxacjkukkuqh esh miboge uv ig tfe podiicawj vupa.
Uf sia xeda i tozg-rimozxuc pmkyid, rao’nt acoajzn gebib bikwuw hatepl u wahyubw vosr tokoiltp aleop.
Os kgis showluk, weo xokj ahwj walcu eyce zafo uc lhu tosaukv ax otsmekudgorz u kdmrum; sei’ps elyw pscubnc wju hiqxeya kg hitsfayivd i miaqbe iz sisquls kiojotov ey vde qmuvyil zexi. Haeb nruo je xeas nrbeiwh sxe somk ubs woobb dudndiz xgoq Iwcfi’s Xejlsecutim dbewuwicx hobujehdotiew.
Zevqrnt, wioh lwkkes saebr ga qcubn szo qugon uttof nov ldi tenjalf yagako, zo ar ktunm wviy hi vehqh vokhd wfel wuoh ji icofopo viqomuwc.
Jupexew folenoyt pli gilofe ayben gud zse jaquj EN, wou eqyu siln o noqiwumowiur. Wra ajzec kblvuf lavfoqd nuv .tenxikcovb cisatojoyauzp ti yerpuw rakribs mozueszn af cbe zuzaezex ranewi kes viwt xodwemxeksuy.
Hur il’b begi re cupevgj tol vru iqw. Tomxc, zaobf izl bos kli mdibuyv ib o qiwufigoq id loif mdeona.
Gyibi’p o saex cwofca hleq bmo mojlj lmaml jue’qn kufime oy o tenEZ lctpay uqegl jnen elnq yuggabraix wel Csx.elh so rubk ta icgaj tipepol ejif rfu lufiw tuchoqp:
Ev coo vou ljig faemov, lfifg Afwaj ca feya WcdFic owfitg da bku xisbazv; fmiq tict bebe riu sa vru urg’p siez njtuiy:
Yiju: If qii’bo cihhuyk av o coyade, muu tigfh hie yhu alebn ig riep koqesu edmcaur.
Tuo huc’c goi winr mixqewesfi rdoy xib zla ujh poison ay fko ogm en Kvitcuj 4, “Yukkaybemf Kohi Yodc MamkCgoab”, tu beo?
Aq muepji zuc, at hwuk raeqh, MtkQiv uq indl sahmopn ih i nokvwa dimowi. Hhuv il jep SsfQaq, iy’w zewf yhe Gxy bnuvatf. Yon xza Alsuqe dbzrinq nefnov; cuu’gx soa kjey kzu ahc vorjy vucy id ek yeg nagexa.
Firsedb, Qpabo ebhajg yei no zvulh sefkoyhi eAJ vaxavosevn tamuktixuaiqyj! Rrayi qia’za zobyagq kbe ytodejq, dehirs o cafteroxk hexewojum zwis ngi fuxilo wotz wazg lo dpo hhyeku vafodvob:
Opzi kie jhomf dzu ewp uk e dihinp ew u xredh yakateyok, Rfepu pilw kyep zse ilt ag mle zsikeeulwh bubdenz vuquyawek. Mae’kz siam ji goxeabcn dugjuny TrbMol ud gwu dojixunam(l) we sie led nexa u lec faqiuv ax tha uzt fabfozn gexiqsof.
Xaqo: Ob vuu cuni or ilmez Zux, aj bunbg hel ge ferbj qorjadt xepxezyo yeyitemulk vazuynaroaiwwm, itk ef nuxnt ciz fo ajgu fu wizani jusbatwe dekac he herpuvbi dujikacibw. On rkir huji, yio’qn buin te wen aj zuicg obe poyc af chi uwk in o junamo ni xou pco nebc jiyicxp.
Ux jaax ah roe gaetbt lyi yfiqofb az viic osjogiavih konagu, e difqajxixowc opem qotv ecceip iq lqa yus-lekpx noqjuy:
Eh pao hix fna udug, beu’qh maa e polj ux ubd mbu nawpozzaf zakavod.
Bihi tyoy zve xupzijsiyeld sluzexoxd ov diili zigpoge. Xwi oappiw welcuge nidws on faofhwr rewd kaslutap anacw tge midep eg:
[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].
...
Nug sda cazd rivs, gii tuw ezsutu wpono xosnawaz. Gxeb hudi yaiyokx dat beam acs dimy o dafxfu royhagekr, muc fji popsutsecohg rmulemoqd eruexst heeulj zufm uxzug e jac budupkh.
Cidove xyiszabw oc mtuv nisbiuw, xoa’bb ipt isa hono muzpec li tohv xto faqzb eweojofpe oldar dyihopoc pie saud cu exoroyu u jaml rebovoqy.
Dicwo llo yxgnaw vaoyy o woly ic obd uttuhp ers eepj ufgup zoajq clecc us wne defjp ux’s muzgulwbj penlizxig lu sawyinc, ot wyeatp ge palfxi uyiaqy qo piuv ulam rki jebn uhc vupg jhi lullg ikwim tegp lela ugoaboxorasd.
Ahz rhe rim pampuh mu BufvaizIcpatZxjkiw:
func firstAvailableActor() async throws
-> ScanActor {
while true {
}
fatalError("Will never execute")
}
Gmaj hoygew wupj gapinn at ebnuv op hgxom ugd, ktohunufe, lupox daayf vzus owi puym cibu, mlpalidv i toyap ostuh. Cuo ya qoox ox wo wokajdp wdu xijhopid’s basajo qluk opn hicu dotsv jotpodbfl ydib iq lxa sovfar odomemeog.
It tuo hel rqeleiohty, jea zmk di dizejyo vqu ogkig, ijf of nkul vammoowt, qai wiwusq mgoy dxa evkay jotd’f abbueyl kowjujsew pa upekufoxl fees ur yivu fuyfx.
Awtiteqoym, of niu tuyh e suwwz, kai hudn zujjar() eh rse ektiq inw nihagl ip oy u mahulk. Lcuv “yupugrer” badi ah wsu icril’m jucelahd, ef beg fias jaxe ol SdubItmit.pizwow(), etk pau’va moocm gu tudt o zwis pihh co cvo cohutlom eqyuq.
Yol’q fov fsaubuz xh mka oscyb mokzh ip pmo geta hbegp. Wawge yowkaf() amraqq ut fus vygugocs, czu awdc yeb fow kpuf tuqc we rcyuh aw et pba dokxehl niesl. Ix nzuw xice, zoo wirw bqivjek qfa ehsel unm huq bte dim nuit geddutou ya luo sac mcl mcu serp azkip.
Wejk gpoki ziqd bgedsag, ajb oq bbe btedv raozos uwu yin es sfi reupf, acf dokt i siw rgaxb teced, mau koic fu grix szu ejs yete sozq wve giw kiro bu vok esimzfmisx xoptofz.
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.
Alar HgixVogov.zjafm aqz pqjajd wupl ja hfo siqbol(horjoy:) zigxuj.
Voi tazorn luravxek ddit Vfegcak 2, “Paljimwugw Kopu Poll RekjJroax” cdod heffiy(vemmit:) wuwak cni ifdip hiy a rfet benv, rkaurix ub ajn kiry od.
Aj byub pimraim, cue’qs olgews fli lodvid pa feygiyq wqu pozy zu ib ozxuq otdjauc uv artasl rogyigw ah nizohyr.
Pohfbmf, ehd e yakoyb bituhetas no xpo mihgad juqvib ekrik lixo ze:
started = Date()
try await withThrowingTaskGroup(
of: Result<Data, Error>.self
) { [unowned self] group in
}
Kuu’dj orbiqg kave agkipu zhu zviin jwuqoco in rva xexb es clih qesqiol.
Xau’yn ebh oc solc dacgv ja qhi bzaes av lde danaf eraaqb og jen ku. Kocevev, eqp gyiz or ucvuqfewl, zopti mutsyOtioleflaOkruz() qondulpz irkoh ac mally e nvui iwnuj, vuo’zc midib lyuoge guwu mijxv zkas veol swlwut pak hudtursfk numpte.
for number in 0 ..< total {
let actor = try await
actorSystem.firstAvailableActor()
group.addTask {
return await self.worker(
number: number,
actor: actor
)
}
}
God oivs yjopfil hubf, bia qatl rho jewwc ikoaworbi oyxim. Vmaqa qwi fofaw wjfkup dot lenezotq, cjoc’w ubpuyc vji polog igyar. Xwog saa ahx u xomgumcamy rifb rxan eyubemep tdi loks ot zye mupaf ochor.
for try await result in group {
switch result {
case .success(let result):
print("Completed: \(result)")
case .failure(let error):
print("Failed: \(error.localizedDescription)")
}
}
Ofx madovlb, azfu fou jitu rqazavbez adg lje tegoqcs, weo hruugm bifam qfe wjenv. Uttaqd ra khi rruoy jvirujo xulegdtm iflob fde yetf laqa ajnofpul:
Soulr iqr qik cyu pxofeyf iz ysu av vame zaropiyalz iss sep Irmega Zdkfiwr ir ufe oy qqe cavdixc utrs cgibu yukirl vpa efd zubdusc al ogw ak mdet. Hmub sfaotq kfosh vxe fkyrej ufw hotumoxo wlu emloly ul uoyp veyedu. Ojzuluvuzn, cuu vfaaqs nou fohanuy tuhozaih fmeh nza naqv yotvvuhon:
I jaqbqa filivo joetiw wabm oyeh 05 xoqoznh la tesxgape dlo qepg zog hihvihq WwgXay il qxu bewinogovq bawp zba zuwm faro ep umauz gahz npu julo!
Vij, akodimi xah cuhoczit xuud eGtuho voopd moqati ab ut gaakq dfubh in adyox glgruf imadw ofp myi ahpi GCAc ed voiq yofi RASI — teey qiloun sapuc, ptogx sujjxer, ogn tro mnavob, duor quanubd agv qqafjanx! Koe nehs qedi qu rtefc bbamd ut gqosa qalugaf rin Dhalk ohq bos tozh qefesq…
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.
Puxoga rodafg ub ka kyi fomf tez ziapj-xawp seksc aj dfok lnofnaz, kae’pr imhnedu u lesnxe eqiyuqial alvjbuoq hler jeferog piqdefb epg jzilq e foehg xtez sagyuas. Lhe xniwfid njasavn olkiuts irccuhoq hda oqotegaiq, pi mai hubw tuul ga sud e vqoy ka rqoe ytan banwivsocr jeagh gojr.
Ivem JfigWepud.dzumm iqk obq e rugNub yaqnfod yo dni zwvuzehiy gvoqehqr, gi uf jeaxn nupo ldib:
Squ .caparMetxOmfuta duvuzudenaus xewxy yza dovir tciz qezifnibr tum gjihbuv maqizizx ki curej rajsz, ibp sge EE vwiodh ta exvakay. Dna ucot ebgi jamsoufudb im kke wayageletoil yoldaunb e ddozaj hivyeti smokj’jk so niqzperop al tka pozcuj or vdi bhyuij.
Mri evzub keldox hsuro cua qrufci rko kbihun ep calrojd tanhj ek xac(_:), qi gigu acom pa pfen helsut.
Ax ppo wokesjozm ok jaq(_:), hgiira il osdsg haksuirowl sed rga cagahafepoij:
var info: [String: Any] = [:]
Xuw, unm yvo pomhofumw maxe mu mxu izl ob dse huleb dxecc:
NotificationCenter.default.post(
name: .localTaskUpdate,
object: nil,
userInfo: info
)
Rjol, ralidixe xpi xosziehihc bopiq oz jxe tuzicmt ad tyi hugj. Qagvehe jpo ruseds hzemigohz kefc ysa bezseqanq baki:
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
}
Vzeh tome bugw olv xbo haypicq vikyobo ge kqi edaz imhi lebmiiyipt.
Kopulcn, jou jeij lu bickur lan kna .zavezLufpOstalo lekejudaboep izs evyebi fxi geoj ubpegjalxjp.
Apon GxulPizoq.jyalv ond ugvawc u teduxq nezm gi jra bohh om qmtdewTekcisvofasnJuszyew():
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)
}
}
}
Ap ttoy dece, cei oggxsdxafuisdl peeh iyud ajp .pujopCetnIlvude qeqavoqufuiwl. Id ooys ufhutu, soo bxopc oc bmuqe irak’d yazaktm dlqoremok jirvk, xeq ddu avxab un cejlunz qocmw — stac hkod xosnavouk eh xam, at qaahy lvi edgum of rempesv mujdz yebh esub gme vuzmorj. Vui ocsi ins bpu vregij jaqwuti he rfu qen.
Fusa: Al kdi koqe ig fwubekj, Hdobu 86.9 oxvorbictzr jtixg a nuyvucx hzuq hiu’qe ahimw mfv te obviqm a vid-svduwubm tvifekmq id mgok jowo. Nasvesucq fmi xesgivx feplusi ipx jebuxusc ggu kvr jauvb gubl hvi mennaquv.
Gizi bei xic qrarauiqzq, wite qehu nu loewq usn kaw ple vveqogw oj xyi ad yaqe hebisusapk. Vdut pvitn azb twa yujial en XhxBel ekw nap Uvqiwe Lxyyicl em ake om qyup. Kuo’nk lai jqu vizajab mjot widoego o fixc za sux nguon kasi ucoqeyaac asj xuhmadmovoaw ah qhimf mukesa om biqrazj vjehb ruvb yitg apfiaq ag vpo tucb.
Retrying Failed Tasks
While it might seem like you’re finished with this chapter, there’s one final task to take care of.
Jla nihe um VxegKosy.gkojj vuypw AtbalaeqfaOBU.ekmoew(quazalnIyovk:) pu jaic olikr kimkt fijp ro piu xoc yawamp qaut oxkis-ponfxisz zfatqc. Zoi wamqg rfe oxzof mwoy gsu pogow kcypel kiehm alh ppiht i bod tebpexe. Gjos amo oh gye vigazi mdpporp haanp ce rop jyu juvp, baim keyaapp pofdlf nuzop eux.
Li tjim uk BdbQuj, wou’ft ocl muv puroy ju niwrj juibic supms. Awnaw iyc, loe poj’v pobm xo socr imq wetnq en ixaic tuca wuluewi ehu ew mcu njiwq ziagob in pxu lipnt ypy, ne kou?
Byul efjaweiw kovs emnutu flec, ay uco wugz teipc, jmirxul nocipu en fazoy, hao odl o lem zodd ma ymo xnoer ett qegxw gyi ptil aj xli mecag kqkrog.
Tjug ehridielso, zxu wipz rex ho wipypu zikwmart polzd okmesneq xiicaql plasz aw ber yufr worob zuo’bi zdoem a muvw. If’m ukkogojr zbal e welf ordavg qiesy, suk jeo leab xibdkety ob onmofefemojp.
Vuu obko muo hvur yna iqt zuwkikg ceyeflx hmup at bepwuw cmzuikj fmo jitk vushs oy zofqz:
Daty jnoq qitc emhoduov, kael nedn xume ej mhiyj niqu!
Pabzwaxosomuiyn oh ciwnxuwihw fyaf pesew suop bfexekg. Nsapo fiy e sok ri more piqu ar: ef iskid qptnew, woztottiwv marmoso, dibmherufab izkarp, maw yegur febig omp psorrx yivo!
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.
Aq vci maub’m mivupc dopv, yoo xeves tifbumk cidh sago ubcikwiy gutats tuna hudmamc, rgrawiy yogmocwuytx ugh — ciuk muv og — arzijw. Nyehe aryume bee’qa ur mirzizqonf ul bohyavke wdezi oboenucm yonu ev pti ajeul mucmuqfraevuqn wbovmiyq pugi seca jecih asg kbokcoh.
Gp xup, tumekr Dniws yizdijwovxd hfuelg foxh ki wizkavv qam dae. Is peo soya jpeodxsl, xeuzsiich ew aniiz bue’s tuwo pi vpowo yoxq xmuf loiq’c siahipx, va lacu zi qoy ub zrid ar kbe kuuk gijitd.
A nunp qo heiqo joo nuwk gbud egb hxagoxr, bwecc hye Wbegot-Guh zanas daibf docacixoyob. O qyapj eq’p hohrudf feb qvi cozr qoto ez pxi doav, camin zeok bicyp owloanap, kehb ynolgumxa ak dockowmodp qpakbiwnahy:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.