Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/promise?V=28
QUERY_STRINGV=28
CONTENT_TYPE
DOCUMENT_URI/revision/promise
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.71.254.202
REMOTE_PORT61842
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR3.147.66.178
HTTP_CF_RAY87dbe1e57bfc2300-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP3.147.66.178
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit promise 2017-11-06:\ promise\ 1.0.3\ released\n\n''Promises''\ are\ concurrency\ primitives\ that\ let\ you\ write\nasynchronous\ code\ in\ a\ sequential\ style.\ The\ `promise`\ package\nis\ a\ Tcl\ based\ implementation\ of\ promises\nmodeled\ for\ the\ most\ part\ on\ the\ Javascript/ECMAScript\ 6\ standard.\n\nProject\ page\ and\ downloads\ are\ at\ http://sourceforge.net/projects/tcl-promise/.\n\nReference\ documentation\ is\ at\ http://tcl-promise.magicsplat.com\ but\nit's\ probably\ best\ to\ start\ with\ the\ posts\ at\ http://www.magicsplat.com/blog/tags/promises/\nfor\ an\ introduction\ with\ examples.\n\n\[APN\]\ In\ response\ to\ a\ question\ on\ the\ chat\ about\ running\ multiple\ du\ programs\n'''in\ parallel''',\ here\ is\ a\ promise\ based\ solution.\ Besides\ printing\ the\ output\nof\ each\ du\ invocation,\ it\ also\ prints\ the\ total\ disk\ usage\ for\ the\ given\npaths\ once\ all\ invocations\ exit.\n\nFirst\ define\ the\ procedures\ to\ handle\ successful\ and\ failed\n(for\ example,\ non-existent\ path)\ completions.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n======\nproc\ on_success\ \{du_output\}\ \{\n\ \ \ \ puts\ \$du_output\n\ \ \ \ #\ Assumes\ a\ very\ specific\ format\ for\ du\ output\ and\ return\ the\ used\ space.\n\ \ \ \ return\ \[scan\ \$du_output\ %d\]\n\}\n\nproc\ on_failure\ \{message\ error_dictionary\}\ \{\n\ \ \ \ puts\ \$message\n\ \ \ \ #\ On\ errors,\ return\ 0\ as\ used\ space\ after\ printing\ the\ error\n\ \ \ \ return\ 0\n\}\n======\n\nAssume\ paths\ contains\ the\ list\ of\ paths\ of\ interest.\n\n======\nset\ paths\ \[list\ c:/Tcl\ c:/Temp\ c:/nosuchpathexists\]\n======\n\nCreate\ a\ promise\ for\ each\ invocation\ of\ du,\ passing\ it\ the\ commands\nto\ call\ on\ successful\ and\ unsuccessful\ completions.\n\n======\nset\ promises\ \[lmap\ path\ \$paths\ \{\n\ \ \ \ set\ promise\ \[promise::pexec\ du\ -sk\ \$path\]\n\ \ \ \ \$promise\ then\ on_success\ on_failure\n\}\]\n======\n\nFinally,\ combine\ all\ the\ promises\ into\ one\ which\ will\ calculate\ the\ntotal\ once\ all\ promises\ are\ fulfilled.\n\n======\nset\ totaller\ \[promise::all\ \$promises\]\n\$totaller\ done\ \[promise::lambda\ \{outputs\}\ \{\n\ \ \ \ puts\ \"Total:\ \[tcl::mathop::+\ \{*\}\$outputs\]\"\n\}\]\n======\n\nNote\ that\ as\ always,\ promises\ require\ the\ Tcl\ event\ loop\ to\ be\ running.\n\nThe\ following\ output\ is\ produced:\n\n======\n/usr/bin/du:\ cannot\ access\ `c:/nosuchpathexists':\ No\ such\ file\ or\ directory\n180149\ \ \ \ \ \ \ \ c:/Temp\n\n229933\ \ \ \ \ \ \ \ c:/Tcl\n\nTotal:\ 410082\n======\n\n**\ Discussion\ **\n\n\[PYK\]\ 2015-04-02:\ Promises\ are\ primarily\ useful\ as\ a\ stop-gap\ until\ a\ language\ngrows\ real\ \[coroutine%|%coroutines\].\ \ Fortunately,\ Tcl\ already\ has\ coroutines.\nFor\ comparison\ here's\ a\ \[coroutine\]\ implementation\ of\ the\ example:\n\n======\n#!\ /bin/env\ tclsh\n\nproc\ du_multi\ \{varname\ args\}\ \{\n\ \ \ \ upvar\ 1\ \$varname\ vname\n\ \ \ \ set\ chans\ \{\}\n\ \ \ \ foreach\ arg\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ chan\ \[open\ |\[list\ du\ -sk\ \$arg\]\]\n\ \ \ \ \ \ \ \ chan\ configure\ \$chan\ -blocking\ 0\n\ \ \ \ \ \ \ \ chan\ event\ \$chan\ readable\ \[list\ \[info\ coroutine\]\ \[list\ \$arg\ \$chan\]\]\n\ \ \ \ \ \ \ \ dict\ set\ chans\ \$chan\ \{\}\n\ \ \ \ \}\n\ \ \ \ while\ \{\[llength\ \[dict\ keys\ \$chans\]\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[yield\]\ dirname\ chan\n\ \ \ \ \ \ \ \ if\ \{\[eof\ \$chan\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dirsize\ \[scan\ \[dict\ get\ \$data\ \$chan\]\ %d\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \[list\ \$dirname\ \$dirsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ total\ \$dirsize\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$chan\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ chans\ \$chan\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ append\ data\ \$chan\ \[read\ \$chan\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ vname\ \$total\n\}\n\n\nproc\ main\ \{argv0\ argv\}\ \{\n\ \ \ \ variable\ total\n\ \ \ \ coroutine\ dm\ du_multi\ total\ \{*\}\$argv\n\ \ \ \ vwait\ total\n\ \ \ \ puts\ \[string\ repeat\ _\ \[string\ length\ \"total\ \$total\"\]\]\n\ \ \ \ puts\ \[list\ total\ \$total\]\n\}\n\nmain\ \$argv0\ \$argv\n======\n\n----\n\n\[APN\]\ Humbly\ begs\ to\ differ.\ I\ see\ coroutines\ as\ one\ way\ that\ promises\ could\ be\ implemented\ in\ a\ language.\ Async\ callbacks\ via\ the\ event\ loop\ is\ another.\ What\ I\ found\ most\ useful\ about\ promises\ is\ the\ \"contracts\"\ they\ define\ that\ allows\ them\ to\ be\ combined\ in\ various\ ways\ (error\ handling\ also\ being\ a\ big\ part\ of\ that).\ Could\ you\ do\ something\ similar\ with\ coroutines?\ Of\ course\ you\ could\ but\ you\ would\ have\ simply\ reimplemented\ a\ promise\ library\ on\ top\ of\ coroutines.\n\n\[PYK\]\ 2016-04-03:\ \ I'm\ just\ really\ curious\ about\ all\ the\ noise\ around\ promises\nand\ futures.\ \ I\ keep\ reading\ about\ them,\ but\ each\ example\ I've\ seen\ looks\ to\ me\nlike\ it\ would\ have\ been\ better-written\ as\ a\ coroutine.\ \ Maybe\ eventually\ this\npage\ will\ sport\ some\ code\ that\ shows\ something\ that\ looks\ better\ with\ promises\nthan\ as\ coroutines.\ \ I'll\ also\ hazard\ a\ prediction\ that\ once\ coroutines\ really\nget\ rolling\ in\ \[Javascript\],\ promises\ will\ fade\ away.\n\n\[APN\]\ 2016-04-04:\ FWIW,\ I\ first\ looked\ at\ promises\ about\ a\ year\ and\ a\ half\ ago\nand\ could\ not\ really\ understand\ the\ fuss\ and\ gave\ up\ on\ a\ Tcl\ version.\ It\ was\ \nonly\ when\ I\ revisited\ them\ much\ later\ that\ things\ sunk\ in.\ Let\ me\ try\ to\ summarize\nthe\ core\ points\ keeping\ in\ mind\ promises\ are\ a\ useful\ tool\ for\ specific\ use\ cases\nand\ not\ a\ panacea.\n\n\ \ \ *\ Computation\ involves\ production\ and\ consumption\ of\ values.\n\ \ \ *\ The\ production\ of\ values\ *may*\ happen\ asynchronously\ but\ not\ necessarily\ so.\n\ \ \ *\ Consumption\ may\ involve\ multiple\ values\ produced\ by\ independent\ producers.\n\ \ \ *\ Consumers\ do\ not\ know\ how\ values\ are\ produced\ (not\ even\ whether\ the\ value\ is\ produced\ asynchronously\ or\ synchronously)\n\ \ \ *\ Producers\ do\ not\ know\ how\ the\ produced\ values\ will\ be\ used\ (essentially\ producers\ and\ consumers\ are\ decoupled).\n\ \ \ *\ The\ completion\ of\ one\ or\ more\ computations\ *may*\ lead\ to\ one\ or\ more\ computations.\ Computations\ thus\ may\ be\ a\ chain\ (directed\ graph\ actually)\ in\ which\ each\ step\ is\ dependent\ on\ the\ results\ of\ one\ or\ more\ prior\ steps.\ \n\ \ \ *\ Any\ computation\ may\ produce\ errors\ or\ exceptions.\n\nIn\ the\ simple\ example\ above,\ each\ invocation\ of\ du\ is\ a\ computation\ that\ produces\ a\nvalue,\ the\ disk\ usage,\ or\ an\ error.\ The\ totaling\ of\ the\ resulting\ value\ is\ also\na\ computation,\ one\ that\ is\ chained\ to\ the\ multiple\ du\ invocations.\ The\ du\ computation\ndoes\ not\ know\ how\ the\ value\ it\ produces\ will\ be\ used.\ The\ totaller\ does\ not\nknow\ how\ its\ input\ values\ were\ produced.\n\nNow\ suppose\ I\ would\ like\ to\ change\ the\ application\ to\ also\ print\ out\ the\ max\ usage.\nAll\ I\ need\ to\ do\ is\ to\ add\ the\ following\ fragment.\n\n======\nset\ maxer\ \[promise::all\ \$promises\]\n\$maxer\ done\ \[promise::lambda\ \{outputs\}\ \{\n\ \ \ \ puts\ \"Max:\ \[tcl::mathfunc::max\ \{*\}\$outputs\]\"\n\}\]\n======\n\nOf\ course\ I\ could\ have\ added\ this\ to\ the\ totaller\ fragment\ as\ well\ but\ ''I\ want\ to\nassume\ that\ the\ consumers\ are\ independent''.\n\nFurthermore,\ once\ both\ results\ are\ done,\ I\ would\ like\ to\ email\ them\ so\ I\ add\nthis.\n\n======\nset\ emailer\ \[promise::all\ \[list\ \$totaller\ \$maxer\]\]\n\$emailer\ done\ \{promise::lambda\ \{total_and_max\}\ \{\n\ \ \ \ email\ [email protected]\ \"Total/max\ were\ \[join\ \$total_and_max\ /\]\"\n\}\n======\n\nAnother\ enhancement\ would\ be\ to\ add\ a\ timeout\ to\ the\ whole\ computation\nto\ abort\ if\ it\ does\ not\ complete\ (see\ the\ blog\ for\ an\ example).\n\nNow,\ with\ your\ coro-based\ du,\ what\ would\ it\ take\ to\ implement\ similar\ enhancements\nthat\ too\ in\ a\ generalized\ manner,\ not\ just\ for\ the\ specific\ example?\nCould\ it\ be\ done?\ Of\ course.\ But\ I\ think\ that\ you\ will\ find\nthat\ by\ the\ time\ you\ refactor\ as\ needed,\ you\ would\ have\ implemented\ some\nform\ of\ the\ promise\ abstraction.\ If\ you\ are\ arguing\ that\ promises\ could\ be\ better\ implemented\ using\ncoroutines\ instead\ of\ the\ event\ loop,\ that\ is\ a\ completely\ different\nargument\ or\ discussion\ but\ I\ don't\ think\ that\ was\ your\ point.\n\nAs\ an\ aside,\ I\ don't\ think\ your\ coro\ has\ the\ same\ behaviour\nas\ the\ promise\ example\ in\ terms\ of\nerror\ handling.\ Consider\ errors\ from\ (a)\ a\ dir\ not\ existing,\ (b)\ dir\nexisting\ but\ no\ access,\ (c)\ the\ du\ program\ not\ being\ present\ on\ the\ system.\nPart\ of\ promises\ has\ to\ do\ with\ the\ relative\ ease\ with\ which\ errors\ncan\ be\ handled\ in\ a\ common\ fragment\ similar\ to\ try\ blocks\ in\ synchronous\ncode.\n\nOne\ final\ comment\ -\ regarding\ your\ comment\ regarding\ promises\ fading,\nit's\ possible\ but\ you\ might\ want\ to\ see\ the\ Scala\ documentation\nas\ an\ example\ of\ languages\ supporting\ both\ facilities\ and\ how\ they\nare\ presented.\ You\ may\ also\ find\ https://blog.domenic.me/youre-missing-the-point-of-promises/%|%this\ post%|%\nfrom\ one\ of\ the\ ES6\ promise\ architects\ illuminating.\n\n\[PYK\]\ 2016-04-06:\ \ That's\ the\ most\ cogent\ and\ accessible\ description\ of\npromises\ I've\ read\ yet,\ and\ it's\ refreshing\ to\ read\ an\ explanation\ that\ isn't\nsteeped\ in\ Javascript.\ \ I\ left\ out\ error\ handling\ in\ my\ example\ because\ I\ would\njust\ write\ any\ desired\ error\ handling\ into\ the\ body\ of\ the\ coroutine,\ as\ usual.\nIt\ would\ be\ trivial\ to\ modify\ the\ ecoroutine\ version\ of\ `du_multi`\ to\ produce\nvalues\ that\ could\ then\ be\ fed\ to\ a\ `maxer`\ or\ `emailer`\ command.\ \ The\ money\nquote\ from\n\[https://blog.domenic.me/youre-missing-the-point-of-promises/%|%You're\ missing\nthe\ point...\]\ is\n\n\ \ \ \ :\ \ \ ''More\ importantly,\ if\ at\ any\ point\ that\ process\ fails,\ one\ function\ in\ the\ composition\ chain\ can\ throw\ an\ exception,\ which\ then\ bypasses\ all\ further\ compositional\ layers\ until\ it\ comes\ into\ the\ hands\ of\ someone\ who\ can\ handle\ it\ with\ a\ catch.''\n\nThen\ there's\ an\ example\ of\ an\ asynchronous\ promise\ chain\ and\ its\ synchronous\nversion.\ \ The\ synchronous\ version\ flows\ better,\ but\ it's\ got\ that\ pesky\ problem\nof\ being\ synchronous.\ \ In\ Tcl,\ it\ seems\ like\ a\ couple\ of\ helper\ procs\ and\ a\ncoroutine\ take\ care\ of\ that:\n\n======\n#\ Cooperating\ producers\ call\ this\ to\ deliver\ results\nproc\ deliver\ \{cmd\ to\}\ \{\n\ \ \ \ catch\ \$cmd\ result\ options\n\ \ \ \ after\ 0\ \[list\ after\ idle\ \[list\ \$to\ \$result\ \$options\]\n\}\n\nproc\ order\ args\ \{\n\ \ \ \ upvar\ result\ myresult\n\ \ \ \ \{*\}\$args\ \[info\ coroutine\]\n\ \ \ \ lassign\ \[yieldto\ return\ -level\ 0\]\ myresult\ options\n\ \ \ \ return\ -options\ \$options\ \$myresult\n\}\n\ncoroutine\ \[info\ cmdcount\]\ \{\{\}\ \{\n\ \ \ \ ...\n\ \ \ \ try\ \{\n\ \ \ \ \ \ set\ tweets\ \[order\ \[getTweetsFor\]\ domenic\]\n\ \ \ \ \ \ set\ shortUrls\ \[parseTweetsForUrls\ tweets\]\n\ \ \ \ \ \ set\ mostRecentShortUrl\ \[lindex\ shortUrls\ 0\]\n\ \ \ \ \ \ set\ responseBody\ \[order\ httpGet\ \[expandUrlUsingTwitterApi\[mostRecentShortUrl\]\]\]\n\ \ \ \ \ \ console\ log\ \[list\ \{Most\ recent\ link\ text\}\ responseBody\]\n\ \ \ \ \}\ catch\ \{\n\ \ \ \ \ \ console\ log\ \[list\ \{Error\ with\ the\ twitterverse\}\ error\n\ \ \ \ \}\n\}\}\n======\n\nI\ don't\ see\ this\ as\ a\ promise\ implementation\ because\ it\ doesn't\ conform\ to\ the\npromise\ API,\ but\ it\ certainly\ shares\ traits\ of\ promises\ such\ as\ passing\ error\ninformation\ along\ with\ results.\ \ Instead\ of\ being\ locked\ down\ to\nsuccess/failure\ responders,\ scripts\ retain\ access\ to\ the\ standard\ Tcl\ error\nhandling\ facilities.\ \ It's\ something\ along\ these\ lines\ that\ I\ suspect\ will\nsupersede\ promises.\ \n\n\[APN\]\ One\ of\ us\ is\ missing\ something.\ I\ freely\ claim\ that's\ you\ :-)\nTo\ use\ an\ (imperfect)\ analogy,\ it\ feels\ to\ me\nlike\ I\ am\ promoting\ the\ benefits\ of\ a\ mail\ protocol\ like\ SMTP\ and\ you\ncome\ back\ stating\ your\ belief\ that\ SMTP\ will\ be\ supplanted\ by\ TCP/IP.\ And\nprovide\ examples\ of\ how\ a\ SMTP-like\ mail\ protocol\ can\ be\ implemented\non\ raw\ TCP/IP\ as\ proof\ of\ this!\ It\ might\ help\ a\ continuing\ discussion\ if\ you\nimplemented\ the\ maxer\ and\ email\ enhancements,\ along\ with\ the\ error\ handling,\nto\ my\ example\ on\ top\ of\ your\ du_multi\ code.\n\n\[PYK\]\ 2016-04-13:\ \ So\ true\ --\ I'm\ quite\ often\ missing\ something!\ \ I\ happen\ to\nbe\ in\ the\ middle\ of\ wrangling\ coroutines\ at\ the\ moment,\ and\ will\ be\ publishing\nsome\ utilties\ that\ have\ come\ of\ the\ experience.\ \ I'll\ also\ work\ through\ the\nexercies\ you\ suggested.\n\n----\n\n\[JHJL\]\ 2018-01-16\ Thank\ you\ for\ providing\ this\ package,\ \[APN\],\ it\ is\ certainly\ getting\ my\ brain\ cells\ busy\ trying\ to\ work\ out\ how\ to\ best\ use\ promises\;\ I\ am\ learning\ many\ Tcl\ tips\ by\ reading\ the\ source\ code.\n\nCurrently,\ \ I\ am\ struggling\ to\ work\ out\ a\ pattern\ for\ accumulating\ a\ set\ of\ record\ field\ values\ from\ a\ REST\ API,\ which\ returns\ N\ records\ at\ a\ time,\ using\ pgeturl.\ I\ can\ repeatedly\ fetch\ each\ batch\ of\ records\ OK,\ but\ my\ pgeturl\ wrapper\ blocks.\ which\ defeats\ the\ object\ of\ using\ promises!\ \ Any\ guidance\ would\ be\ welcome.\n\nAs\ an\ aside,\ I\ had\ a\ situation\ this\ morning\ where\ the\ target\ server\ was\ down\ causing\ a\ socket\ error.\ I\ am\ pondering\ whether\ or\ not\ this\ error\ should\ be\ trapped\ by\ pgeturl\ (and\ presumably\ other\ socket\ based\ calls)\ and\ returned\ through\ the\ \ REJECTED\ mechanism.\n\n\[APN\]\ Can\ you\ show\ the\ code?\ Difficult\ to\ make\ a\ suggestion\ as\ it\ is\ not\ clear\ exactly\ what\ you\ are\ doing.\ Do\ you\ have\ to\ wait\ for\ a\ previous\ request\ to\ complete\ before\ sending\ the\ next\ one?\ If\ so,\ the\ async/await\ command\ pair\ will\ likely\ help.\ Regarding\ the\ socket\ error,\ how\ does\ the\ error\ manifest\ itself?\ Again\ without\ seeing\ code,\ it\ is\ hard\ to\ make\ any\ suggestions.\n\n\[JHJL\]\ Abridged\ lowlights\ \;)\ Basically,\ I\ want\ to\ call\ pickfields\ products\ \{id\ sku\ name\}\ \{limit\ 100\}\ and\ get\ notified\ when\ a\ list\ of\ \ all\ \ \{id\ sku\ name\}\ records\ (possibly\ 1000s)\ are\ available\n\n======\nasync\ pickfields\ \{path\ fields\ \{params\ \{\}\}\}\ \{\n\n\ \ set\ result\ \[list\]\n\ \ set\ defaults\ \[dict\ create\ limit\ 20\ page\ 0\]\n\ \ set\ params\ \[dict\ merge\ \$defaults\ \$params\]\n\n\ \ set\ got\ \[set\ limit\ \[dict\ get\ \$params\ limit\]\]\n\n\ \ while\ \{\$got\ ==\ \$limit\ \}\ \ \{\n\n\ \ \ \ dict\ incr\ params\ page\n\n\ \ \ \ set\ state\ \[await\ \[pg\ \$path\ \$params\]\]\n\n\ \ \ \ set\ jsn\ \[dict\ get\ \$state\ body\]\n\n\ \ \ \ if\ \{\$fields\ !=\ \{\}\}\ \{\n\ \ \ \ \ \ lappend\ result\ \[pickkeyed\ \$jsn\ \{*\}\$fields\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ lappend\ result\ \[json\ get\ \$jsn\]\n\ \ \ \ \}\n\ \ \ \ set\ got\ \[jsoncount\ \$jsn\]\ \n\n\ \ \}\n\ \ return\ \$result\n\}\n\n#\ A\ little\ helper,\ returns\ a\ promise\nproc\ pg\ \{path\ params\}\ \{\n\ \ #\ get\ API\ URL\ with\ parameters\ e.g.\ given\ products\ \{limit\ 100\}\ ->\ \ https://host.com/path?limit=100\n\ \ set\ url\ \ \ \ \ \[_mkurl\ \ \ \ \$path\ \$params\]\n\ \ #\ OAUTH\ signature\n\ \ set\ oauth\ \ \ \[_getoauth\ GET\ \$path\ \$params\]\n\n\ \ pgeturl\ \\\n\ \ \ \ \$url\ \ \\\n\ \ \ \ -blocksize\ \[expr\ \{2\ **\ 20\}\]\ \\\n\ \ \ \ -headers\ \[list\ \\\n\ \ \ \ \ \ \ \ Authorization\ \$oauth\ \\\n\ \ \ \ \ \ \ \ Content-type=\ \"application/json\"\ \\\n\ \ \ \ \]\n\}\n\n#\ Get\ named\ fields\ from\ either\ a\ JSON\ object\ or\ a\ JSON\ array\nproc\ pickkeyed\ \{json\ args\}\ \{\n\ \ \ \ \n\ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 0\}\ \ \{\n\ \ \ \ \ \ \ \ #\ No\ field\ list\ -\ return\ everything\n\ \ \ \ \ \ \ \ return\ \[::rl_json::json\ get\ \$json\]\n\ \ \ \ \}\n\n\ \ \ \ set\ type\ \[rl_json::json\ type\ \$json\]\n\n\ \ \ \ if\ \{\ \$type\ eq\ \"object\"\}\ \{\n\ \ \ \ \ \ \ \ return\ \[rl_json::json\ lmap\ \{key\ val\}\ \$json\ \{pick\ \$val\ \{*\}\$args\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ return\ \[rl_json::json\ lmap\ \{val\}\ \$json\ \{pick\ \$val\ \{*\}\$args\}\]\n\ \ \ \ \}\n\}\n\n#\ Number\ of\ records\ in\ a\ JSON\ object/array\nproc\ jsoncount\ \{jsn\}\ \{\n\ \ expr\ \{\ \[rl_json::json\ type\ \$jsn\]\ eq\ \"object\"\ ?\ \[rl_json::json\ get\ \$jsn\ ?size\]\ :\ \[rl_json::json\ get\ \$jsn\ ?length\]\}\n\}\n\n#\ get\ named\ fields\ from\ JSON\ object\nproc\ pick\ \{jsn\ args\}\ \{\n\ \ foreach\ a\ \$args\ \{\n\ \ \ \ if\ \{\[rl_json::json\ exists\ \$jsn\ \$a\]\}\ \{\n\ \ \ \ \ \ lappend\ result\ \$a\ \[rl_json::json\ get\ \$jsn\ \$a\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ return\ -code\ error\ \"unknown\ field\ '\$a'\"\n\ \ \ \ \}\n\ \ \}\n\ \ return\ \$result\n\}\n\n======\n\n\[APN\]\ At\ first\ glance,\ that\ code\ looks\ reasonable.\ Obviously\ cannot\ run\ it\ to\ \ntry\ it\ out\ and\ see\ the\ failure\ since\ it\ needs\ the\ authentication\ bits\ and\ url.\nI'll\ try\ to\ modify\ it\ to\ an\ example\ that\ works\ similarly\ and\ see\ if\ I\ can\ntroubleshoot\ it.\ I\ presume\ you\ are\ doing\ something\ like\n\n======\n\nset\ prom\ \[pickfields\ http://www.example.com\ \{fieldA\ fieldB\}\]\n\$prom\ done\ \[lambda\ args\ \{puts\ \"Success:\ \$args\"\}\]\ \[lambda\ args\ \{puts\ \"Error:\ \$args\"\}\]\n\n======\n\nand\ that\ by\ \"blocks\"\ you\ mean\ neither\ of\ the\ actions\ passed\ to\ the\ `done`\ method\ fires.\nAm\ I\ right?\n\nRegarding\ the\ socket\ error,\ do\ you\ have\ a\ stack\ trace?\ All\ errors\ within\ `pgeturl`\ \nshould\ be\ converted\ to\ REJECT\ actions.\ I\ would\ consider\ it\ a\ bug\ (hopefully\ fixable)\nif\ that\ is\ not\ the\ case.\ A\ stack\ trace\ (errorInfo)\ would\ be\ useful\ to\ see\ if\ that\nis\ the\ case.\n\n\n======\n\n<<categories>>\ Concurrency\ |\ coroutine regexp2} CALL {my render promise 2017-11-06:\ promise\ 1.0.3\ released\n\n''Promises''\ are\ concurrency\ primitives\ that\ let\ you\ write\nasynchronous\ code\ in\ a\ sequential\ style.\ The\ `promise`\ package\nis\ a\ Tcl\ based\ implementation\ of\ promises\nmodeled\ for\ the\ most\ part\ on\ the\ Javascript/ECMAScript\ 6\ standard.\n\nProject\ page\ and\ downloads\ are\ at\ http://sourceforge.net/projects/tcl-promise/.\n\nReference\ documentation\ is\ at\ http://tcl-promise.magicsplat.com\ but\nit's\ probably\ best\ to\ start\ with\ the\ posts\ at\ http://www.magicsplat.com/blog/tags/promises/\nfor\ an\ introduction\ with\ examples.\n\n\[APN\]\ In\ response\ to\ a\ question\ on\ the\ chat\ about\ running\ multiple\ du\ programs\n'''in\ parallel''',\ here\ is\ a\ promise\ based\ solution.\ Besides\ printing\ the\ output\nof\ each\ du\ invocation,\ it\ also\ prints\ the\ total\ disk\ usage\ for\ the\ given\npaths\ once\ all\ invocations\ exit.\n\nFirst\ define\ the\ procedures\ to\ handle\ successful\ and\ failed\n(for\ example,\ non-existent\ path)\ completions.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n======\nproc\ on_success\ \{du_output\}\ \{\n\ \ \ \ puts\ \$du_output\n\ \ \ \ #\ Assumes\ a\ very\ specific\ format\ for\ du\ output\ and\ return\ the\ used\ space.\n\ \ \ \ return\ \[scan\ \$du_output\ %d\]\n\}\n\nproc\ on_failure\ \{message\ error_dictionary\}\ \{\n\ \ \ \ puts\ \$message\n\ \ \ \ #\ On\ errors,\ return\ 0\ as\ used\ space\ after\ printing\ the\ error\n\ \ \ \ return\ 0\n\}\n======\n\nAssume\ paths\ contains\ the\ list\ of\ paths\ of\ interest.\n\n======\nset\ paths\ \[list\ c:/Tcl\ c:/Temp\ c:/nosuchpathexists\]\n======\n\nCreate\ a\ promise\ for\ each\ invocation\ of\ du,\ passing\ it\ the\ commands\nto\ call\ on\ successful\ and\ unsuccessful\ completions.\n\n======\nset\ promises\ \[lmap\ path\ \$paths\ \{\n\ \ \ \ set\ promise\ \[promise::pexec\ du\ -sk\ \$path\]\n\ \ \ \ \$promise\ then\ on_success\ on_failure\n\}\]\n======\n\nFinally,\ combine\ all\ the\ promises\ into\ one\ which\ will\ calculate\ the\ntotal\ once\ all\ promises\ are\ fulfilled.\n\n======\nset\ totaller\ \[promise::all\ \$promises\]\n\$totaller\ done\ \[promise::lambda\ \{outputs\}\ \{\n\ \ \ \ puts\ \"Total:\ \[tcl::mathop::+\ \{*\}\$outputs\]\"\n\}\]\n======\n\nNote\ that\ as\ always,\ promises\ require\ the\ Tcl\ event\ loop\ to\ be\ running.\n\nThe\ following\ output\ is\ produced:\n\n======\n/usr/bin/du:\ cannot\ access\ `c:/nosuchpathexists':\ No\ such\ file\ or\ directory\n180149\ \ \ \ \ \ \ \ c:/Temp\n\n229933\ \ \ \ \ \ \ \ c:/Tcl\n\nTotal:\ 410082\n======\n\n**\ Discussion\ **\n\n\[PYK\]\ 2015-04-02:\ Promises\ are\ primarily\ useful\ as\ a\ stop-gap\ until\ a\ language\ngrows\ real\ \[coroutine%|%coroutines\].\ \ Fortunately,\ Tcl\ already\ has\ coroutines.\nFor\ comparison\ here's\ a\ \[coroutine\]\ implementation\ of\ the\ example:\n\n======\n#!\ /bin/env\ tclsh\n\nproc\ du_multi\ \{varname\ args\}\ \{\n\ \ \ \ upvar\ 1\ \$varname\ vname\n\ \ \ \ set\ chans\ \{\}\n\ \ \ \ foreach\ arg\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ chan\ \[open\ |\[list\ du\ -sk\ \$arg\]\]\n\ \ \ \ \ \ \ \ chan\ configure\ \$chan\ -blocking\ 0\n\ \ \ \ \ \ \ \ chan\ event\ \$chan\ readable\ \[list\ \[info\ coroutine\]\ \[list\ \$arg\ \$chan\]\]\n\ \ \ \ \ \ \ \ dict\ set\ chans\ \$chan\ \{\}\n\ \ \ \ \}\n\ \ \ \ while\ \{\[llength\ \[dict\ keys\ \$chans\]\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[yield\]\ dirname\ chan\n\ \ \ \ \ \ \ \ if\ \{\[eof\ \$chan\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dirsize\ \[scan\ \[dict\ get\ \$data\ \$chan\]\ %d\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \[list\ \$dirname\ \$dirsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ total\ \$dirsize\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$chan\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ chans\ \$chan\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ append\ data\ \$chan\ \[read\ \$chan\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ vname\ \$total\n\}\n\n\nproc\ main\ \{argv0\ argv\}\ \{\n\ \ \ \ variable\ total\n\ \ \ \ coroutine\ dm\ du_multi\ total\ \{*\}\$argv\n\ \ \ \ vwait\ total\n\ \ \ \ puts\ \[string\ repeat\ _\ \[string\ length\ \"total\ \$total\"\]\]\n\ \ \ \ puts\ \[list\ total\ \$total\]\n\}\n\nmain\ \$argv0\ \$argv\n======\n\n----\n\n\[APN\]\ Humbly\ begs\ to\ differ.\ I\ see\ coroutines\ as\ one\ way\ that\ promises\ could\ be\ implemented\ in\ a\ language.\ Async\ callbacks\ via\ the\ event\ loop\ is\ another.\ What\ I\ found\ most\ useful\ about\ promises\ is\ the\ \"contracts\"\ they\ define\ that\ allows\ them\ to\ be\ combined\ in\ various\ ways\ (error\ handling\ also\ being\ a\ big\ part\ of\ that).\ Could\ you\ do\ something\ similar\ with\ coroutines?\ Of\ course\ you\ could\ but\ you\ would\ have\ simply\ reimplemented\ a\ promise\ library\ on\ top\ of\ coroutines.\n\n\[PYK\]\ 2016-04-03:\ \ I'm\ just\ really\ curious\ about\ all\ the\ noise\ around\ promises\nand\ futures.\ \ I\ keep\ reading\ about\ them,\ but\ each\ example\ I've\ seen\ looks\ to\ me\nlike\ it\ would\ have\ been\ better-written\ as\ a\ coroutine.\ \ Maybe\ eventually\ this\npage\ will\ sport\ some\ code\ that\ shows\ something\ that\ looks\ better\ with\ promises\nthan\ as\ coroutines.\ \ I'll\ also\ hazard\ a\ prediction\ that\ once\ coroutines\ really\nget\ rolling\ in\ \[Javascript\],\ promises\ will\ fade\ away.\n\n\[APN\]\ 2016-04-04:\ FWIW,\ I\ first\ looked\ at\ promises\ about\ a\ year\ and\ a\ half\ ago\nand\ could\ not\ really\ understand\ the\ fuss\ and\ gave\ up\ on\ a\ Tcl\ version.\ It\ was\ \nonly\ when\ I\ revisited\ them\ much\ later\ that\ things\ sunk\ in.\ Let\ me\ try\ to\ summarize\nthe\ core\ points\ keeping\ in\ mind\ promises\ are\ a\ useful\ tool\ for\ specific\ use\ cases\nand\ not\ a\ panacea.\n\n\ \ \ *\ Computation\ involves\ production\ and\ consumption\ of\ values.\n\ \ \ *\ The\ production\ of\ values\ *may*\ happen\ asynchronously\ but\ not\ necessarily\ so.\n\ \ \ *\ Consumption\ may\ involve\ multiple\ values\ produced\ by\ independent\ producers.\n\ \ \ *\ Consumers\ do\ not\ know\ how\ values\ are\ produced\ (not\ even\ whether\ the\ value\ is\ produced\ asynchronously\ or\ synchronously)\n\ \ \ *\ Producers\ do\ not\ know\ how\ the\ produced\ values\ will\ be\ used\ (essentially\ producers\ and\ consumers\ are\ decoupled).\n\ \ \ *\ The\ completion\ of\ one\ or\ more\ computations\ *may*\ lead\ to\ one\ or\ more\ computations.\ Computations\ thus\ may\ be\ a\ chain\ (directed\ graph\ actually)\ in\ which\ each\ step\ is\ dependent\ on\ the\ results\ of\ one\ or\ more\ prior\ steps.\ \n\ \ \ *\ Any\ computation\ may\ produce\ errors\ or\ exceptions.\n\nIn\ the\ simple\ example\ above,\ each\ invocation\ of\ du\ is\ a\ computation\ that\ produces\ a\nvalue,\ the\ disk\ usage,\ or\ an\ error.\ The\ totaling\ of\ the\ resulting\ value\ is\ also\na\ computation,\ one\ that\ is\ chained\ to\ the\ multiple\ du\ invocations.\ The\ du\ computation\ndoes\ not\ know\ how\ the\ value\ it\ produces\ will\ be\ used.\ The\ totaller\ does\ not\nknow\ how\ its\ input\ values\ were\ produced.\n\nNow\ suppose\ I\ would\ like\ to\ change\ the\ application\ to\ also\ print\ out\ the\ max\ usage.\nAll\ I\ need\ to\ do\ is\ to\ add\ the\ following\ fragment.\n\n======\nset\ maxer\ \[promise::all\ \$promises\]\n\$maxer\ done\ \[promise::lambda\ \{outputs\}\ \{\n\ \ \ \ puts\ \"Max:\ \[tcl::mathfunc::max\ \{*\}\$outputs\]\"\n\}\]\n======\n\nOf\ course\ I\ could\ have\ added\ this\ to\ the\ totaller\ fragment\ as\ well\ but\ ''I\ want\ to\nassume\ that\ the\ consumers\ are\ independent''.\n\nFurthermore,\ once\ both\ results\ are\ done,\ I\ would\ like\ to\ email\ them\ so\ I\ add\nthis.\n\n======\nset\ emailer\ \[promise::all\ \[list\ \$totaller\ \$maxer\]\]\n\$emailer\ done\ \{promise::lambda\ \{total_and_max\}\ \{\n\ \ \ \ email\ [email protected]\ \"Total/max\ were\ \[join\ \$total_and_max\ /\]\"\n\}\n======\n\nAnother\ enhancement\ would\ be\ to\ add\ a\ timeout\ to\ the\ whole\ computation\nto\ abort\ if\ it\ does\ not\ complete\ (see\ the\ blog\ for\ an\ example).\n\nNow,\ with\ your\ coro-based\ du,\ what\ would\ it\ take\ to\ implement\ similar\ enhancements\nthat\ too\ in\ a\ generalized\ manner,\ not\ just\ for\ the\ specific\ example?\nCould\ it\ be\ done?\ Of\ course.\ But\ I\ think\ that\ you\ will\ find\nthat\ by\ the\ time\ you\ refactor\ as\ needed,\ you\ would\ have\ implemented\ some\nform\ of\ the\ promise\ abstraction.\ If\ you\ are\ arguing\ that\ promises\ could\ be\ better\ implemented\ using\ncoroutines\ instead\ of\ the\ event\ loop,\ that\ is\ a\ completely\ different\nargument\ or\ discussion\ but\ I\ don't\ think\ that\ was\ your\ point.\n\nAs\ an\ aside,\ I\ don't\ think\ your\ coro\ has\ the\ same\ behaviour\nas\ the\ promise\ example\ in\ terms\ of\nerror\ handling.\ Consider\ errors\ from\ (a)\ a\ dir\ not\ existing,\ (b)\ dir\nexisting\ but\ no\ access,\ (c)\ the\ du\ program\ not\ being\ present\ on\ the\ system.\nPart\ of\ promises\ has\ to\ do\ with\ the\ relative\ ease\ with\ which\ errors\ncan\ be\ handled\ in\ a\ common\ fragment\ similar\ to\ try\ blocks\ in\ synchronous\ncode.\n\nOne\ final\ comment\ -\ regarding\ your\ comment\ regarding\ promises\ fading,\nit's\ possible\ but\ you\ might\ want\ to\ see\ the\ Scala\ documentation\nas\ an\ example\ of\ languages\ supporting\ both\ facilities\ and\ how\ they\nare\ presented.\ You\ may\ also\ find\ https://blog.domenic.me/youre-missing-the-point-of-promises/%|%this\ post%|%\nfrom\ one\ of\ the\ ES6\ promise\ architects\ illuminating.\n\n\[PYK\]\ 2016-04-06:\ \ That's\ the\ most\ cogent\ and\ accessible\ description\ of\npromises\ I've\ read\ yet,\ and\ it's\ refreshing\ to\ read\ an\ explanation\ that\ isn't\nsteeped\ in\ Javascript.\ \ I\ left\ out\ error\ handling\ in\ my\ example\ because\ I\ would\njust\ write\ any\ desired\ error\ handling\ into\ the\ body\ of\ the\ coroutine,\ as\ usual.\nIt\ would\ be\ trivial\ to\ modify\ the\ ecoroutine\ version\ of\ `du_multi`\ to\ produce\nvalues\ that\ could\ then\ be\ fed\ to\ a\ `maxer`\ or\ `emailer`\ command.\ \ The\ money\nquote\ from\n\[https://blog.domenic.me/youre-missing-the-point-of-promises/%|%You're\ missing\nthe\ point...\]\ is\n\n\ \ \ \ :\ \ \ ''More\ importantly,\ if\ at\ any\ point\ that\ process\ fails,\ one\ function\ in\ the\ composition\ chain\ can\ throw\ an\ exception,\ which\ then\ bypasses\ all\ further\ compositional\ layers\ until\ it\ comes\ into\ the\ hands\ of\ someone\ who\ can\ handle\ it\ with\ a\ catch.''\n\nThen\ there's\ an\ example\ of\ an\ asynchronous\ promise\ chain\ and\ its\ synchronous\nversion.\ \ The\ synchronous\ version\ flows\ better,\ but\ it's\ got\ that\ pesky\ problem\nof\ being\ synchronous.\ \ In\ Tcl,\ it\ seems\ like\ a\ couple\ of\ helper\ procs\ and\ a\ncoroutine\ take\ care\ of\ that:\n\n======\n#\ Cooperating\ producers\ call\ this\ to\ deliver\ results\nproc\ deliver\ \{cmd\ to\}\ \{\n\ \ \ \ catch\ \$cmd\ result\ options\n\ \ \ \ after\ 0\ \[list\ after\ idle\ \[list\ \$to\ \$result\ \$options\]\n\}\n\nproc\ order\ args\ \{\n\ \ \ \ upvar\ result\ myresult\n\ \ \ \ \{*\}\$args\ \[info\ coroutine\]\n\ \ \ \ lassign\ \[yieldto\ return\ -level\ 0\]\ myresult\ options\n\ \ \ \ return\ -options\ \$options\ \$myresult\n\}\n\ncoroutine\ \[info\ cmdcount\]\ \{\{\}\ \{\n\ \ \ \ ...\n\ \ \ \ try\ \{\n\ \ \ \ \ \ set\ tweets\ \[order\ \[getTweetsFor\]\ domenic\]\n\ \ \ \ \ \ set\ shortUrls\ \[parseTweetsForUrls\ tweets\]\n\ \ \ \ \ \ set\ mostRecentShortUrl\ \[lindex\ shortUrls\ 0\]\n\ \ \ \ \ \ set\ responseBody\ \[order\ httpGet\ \[expandUrlUsingTwitterApi\[mostRecentShortUrl\]\]\]\n\ \ \ \ \ \ console\ log\ \[list\ \{Most\ recent\ link\ text\}\ responseBody\]\n\ \ \ \ \}\ catch\ \{\n\ \ \ \ \ \ console\ log\ \[list\ \{Error\ with\ the\ twitterverse\}\ error\n\ \ \ \ \}\n\}\}\n======\n\nI\ don't\ see\ this\ as\ a\ promise\ implementation\ because\ it\ doesn't\ conform\ to\ the\npromise\ API,\ but\ it\ certainly\ shares\ traits\ of\ promises\ such\ as\ passing\ error\ninformation\ along\ with\ results.\ \ Instead\ of\ being\ locked\ down\ to\nsuccess/failure\ responders,\ scripts\ retain\ access\ to\ the\ standard\ Tcl\ error\nhandling\ facilities.\ \ It's\ something\ along\ these\ lines\ that\ I\ suspect\ will\nsupersede\ promises.\ \n\n\[APN\]\ One\ of\ us\ is\ missing\ something.\ I\ freely\ claim\ that's\ you\ :-)\nTo\ use\ an\ (imperfect)\ analogy,\ it\ feels\ to\ me\nlike\ I\ am\ promoting\ the\ benefits\ of\ a\ mail\ protocol\ like\ SMTP\ and\ you\ncome\ back\ stating\ your\ belief\ that\ SMTP\ will\ be\ supplanted\ by\ TCP/IP.\ And\nprovide\ examples\ of\ how\ a\ SMTP-like\ mail\ protocol\ can\ be\ implemented\non\ raw\ TCP/IP\ as\ proof\ of\ this!\ It\ might\ help\ a\ continuing\ discussion\ if\ you\nimplemented\ the\ maxer\ and\ email\ enhancements,\ along\ with\ the\ error\ handling,\nto\ my\ example\ on\ top\ of\ your\ du_multi\ code.\n\n\[PYK\]\ 2016-04-13:\ \ So\ true\ --\ I'm\ quite\ often\ missing\ something!\ \ I\ happen\ to\nbe\ in\ the\ middle\ of\ wrangling\ coroutines\ at\ the\ moment,\ and\ will\ be\ publishing\nsome\ utilties\ that\ have\ come\ of\ the\ experience.\ \ I'll\ also\ work\ through\ the\nexercies\ you\ suggested.\n\n----\n\n\[JHJL\]\ 2018-01-16\ Thank\ you\ for\ providing\ this\ package,\ \[APN\],\ it\ is\ certainly\ getting\ my\ brain\ cells\ busy\ trying\ to\ work\ out\ how\ to\ best\ use\ promises\;\ I\ am\ learning\ many\ Tcl\ tips\ by\ reading\ the\ source\ code.\n\nCurrently,\ \ I\ am\ struggling\ to\ work\ out\ a\ pattern\ for\ accumulating\ a\ set\ of\ record\ field\ values\ from\ a\ REST\ API,\ which\ returns\ N\ records\ at\ a\ time,\ using\ pgeturl.\ I\ can\ repeatedly\ fetch\ each\ batch\ of\ records\ OK,\ but\ my\ pgeturl\ wrapper\ blocks.\ which\ defeats\ the\ object\ of\ using\ promises!\ \ Any\ guidance\ would\ be\ welcome.\n\nAs\ an\ aside,\ I\ had\ a\ situation\ this\ morning\ where\ the\ target\ server\ was\ down\ causing\ a\ socket\ error.\ I\ am\ pondering\ whether\ or\ not\ this\ error\ should\ be\ trapped\ by\ pgeturl\ (and\ presumably\ other\ socket\ based\ calls)\ and\ returned\ through\ the\ \ REJECTED\ mechanism.\n\n\[APN\]\ Can\ you\ show\ the\ code?\ Difficult\ to\ make\ a\ suggestion\ as\ it\ is\ not\ clear\ exactly\ what\ you\ are\ doing.\ Do\ you\ have\ to\ wait\ for\ a\ previous\ request\ to\ complete\ before\ sending\ the\ next\ one?\ If\ so,\ the\ async/await\ command\ pair\ will\ likely\ help.\ Regarding\ the\ socket\ error,\ how\ does\ the\ error\ manifest\ itself?\ Again\ without\ seeing\ code,\ it\ is\ hard\ to\ make\ any\ suggestions.\n\n\[JHJL\]\ Abridged\ lowlights\ \;)\ Basically,\ I\ want\ to\ call\ pickfields\ products\ \{id\ sku\ name\}\ \{limit\ 100\}\ and\ get\ notified\ when\ a\ list\ of\ \ all\ \ \{id\ sku\ name\}\ records\ (possibly\ 1000s)\ are\ available\n\n======\nasync\ pickfields\ \{path\ fields\ \{params\ \{\}\}\}\ \{\n\n\ \ set\ result\ \[list\]\n\ \ set\ defaults\ \[dict\ create\ limit\ 20\ page\ 0\]\n\ \ set\ params\ \[dict\ merge\ \$defaults\ \$params\]\n\n\ \ set\ got\ \[set\ limit\ \[dict\ get\ \$params\ limit\]\]\n\n\ \ while\ \{\$got\ ==\ \$limit\ \}\ \ \{\n\n\ \ \ \ dict\ incr\ params\ page\n\n\ \ \ \ set\ state\ \[await\ \[pg\ \$path\ \$params\]\]\n\n\ \ \ \ set\ jsn\ \[dict\ get\ \$state\ body\]\n\n\ \ \ \ if\ \{\$fields\ !=\ \{\}\}\ \{\n\ \ \ \ \ \ lappend\ result\ \[pickkeyed\ \$jsn\ \{*\}\$fields\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ lappend\ result\ \[json\ get\ \$jsn\]\n\ \ \ \ \}\n\ \ \ \ set\ got\ \[jsoncount\ \$jsn\]\ \n\n\ \ \}\n\ \ return\ \$result\n\}\n\n#\ A\ little\ helper,\ returns\ a\ promise\nproc\ pg\ \{path\ params\}\ \{\n\ \ #\ get\ API\ URL\ with\ parameters\ e.g.\ given\ products\ \{limit\ 100\}\ ->\ \ https://host.com/path?limit=100\n\ \ set\ url\ \ \ \ \ \[_mkurl\ \ \ \ \$path\ \$params\]\n\ \ #\ OAUTH\ signature\n\ \ set\ oauth\ \ \ \[_getoauth\ GET\ \$path\ \$params\]\n\n\ \ pgeturl\ \\\n\ \ \ \ \$url\ \ \\\n\ \ \ \ -blocksize\ \[expr\ \{2\ **\ 20\}\]\ \\\n\ \ \ \ -headers\ \[list\ \\\n\ \ \ \ \ \ \ \ Authorization\ \$oauth\ \\\n\ \ \ \ \ \ \ \ Content-type=\ \"application/json\"\ \\\n\ \ \ \ \]\n\}\n\n#\ Get\ named\ fields\ from\ either\ a\ JSON\ object\ or\ a\ JSON\ array\nproc\ pickkeyed\ \{json\ args\}\ \{\n\ \ \ \ \n\ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 0\}\ \ \{\n\ \ \ \ \ \ \ \ #\ No\ field\ list\ -\ return\ everything\n\ \ \ \ \ \ \ \ return\ \[::rl_json::json\ get\ \$json\]\n\ \ \ \ \}\n\n\ \ \ \ set\ type\ \[rl_json::json\ type\ \$json\]\n\n\ \ \ \ if\ \{\ \$type\ eq\ \"object\"\}\ \{\n\ \ \ \ \ \ \ \ return\ \[rl_json::json\ lmap\ \{key\ val\}\ \$json\ \{pick\ \$val\ \{*\}\$args\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ return\ \[rl_json::json\ lmap\ \{val\}\ \$json\ \{pick\ \$val\ \{*\}\$args\}\]\n\ \ \ \ \}\n\}\n\n#\ Number\ of\ records\ in\ a\ JSON\ object/array\nproc\ jsoncount\ \{jsn\}\ \{\n\ \ expr\ \{\ \[rl_json::json\ type\ \$jsn\]\ eq\ \"object\"\ ?\ \[rl_json::json\ get\ \$jsn\ ?size\]\ :\ \[rl_json::json\ get\ \$jsn\ ?length\]\}\n\}\n\n#\ get\ named\ fields\ from\ JSON\ object\nproc\ pick\ \{jsn\ args\}\ \{\n\ \ foreach\ a\ \$args\ \{\n\ \ \ \ if\ \{\[rl_json::json\ exists\ \$jsn\ \$a\]\}\ \{\n\ \ \ \ \ \ lappend\ result\ \$a\ \[rl_json::json\ get\ \$jsn\ \$a\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ return\ -code\ error\ \"unknown\ field\ '\$a'\"\n\ \ \ \ \}\n\ \ \}\n\ \ return\ \$result\n\}\n\n======\n\n\[APN\]\ At\ first\ glance,\ that\ code\ looks\ reasonable.\ Obviously\ cannot\ run\ it\ to\ \ntry\ it\ out\ and\ see\ the\ failure\ since\ it\ needs\ the\ authentication\ bits\ and\ url.\nI'll\ try\ to\ modify\ it\ to\ an\ example\ that\ works\ similarly\ and\ see\ if\ I\ can\ntroubleshoot\ it.\ I\ presume\ you\ are\ doing\ something\ like\n\n======\n\nset\ prom\ \[pickfields\ http://www.example.com\ \{fieldA\ fieldB\}\]\n\$prom\ done\ \[lambda\ args\ \{puts\ \"Success:\ \$args\"\}\]\ \[lambda\ args\ \{puts\ \"Error:\ \$args\"\}\]\n\n======\n\nand\ that\ by\ \"blocks\"\ you\ mean\ neither\ of\ the\ actions\ passed\ to\ the\ `done`\ method\ fires.\nAm\ I\ right?\n\nRegarding\ the\ socket\ error,\ do\ you\ have\ a\ stack\ trace?\ All\ errors\ within\ `pgeturl`\ \nshould\ be\ converted\ to\ REJECT\ actions.\ I\ would\ consider\ it\ a\ bug\ (hopefully\ fixable)\nif\ that\ is\ not\ the\ case.\ A\ stack\ trace\ (errorInfo)\ would\ be\ useful\ to\ see\ if\ that\nis\ the\ case.\n\n\n======\n\n<<categories>>\ Concurrency\ |\ coroutine} CALL {my revision promise} CALL {::oo::Obj4416021 process revision/promise} CALL {::oo::Obj4416019 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4