
Pavel
19.07.2018
06:35:06
потому что между узлами сообщения ходят по сети через udp

Ayrat
19.07.2018
06:35:28
это вообще неважно, абстрагируемся за Async<>
если не можешь абстрагироваться, оберни синхронный вызов в async {} :D
для начала сойдёт

Google

Pavel
19.07.2018
06:36:52
возможно, мы немного про разное говорим

Ayrat
19.07.2018
06:37:01
очень вероятно

Pavel
19.07.2018
06:37:10
udp => нет понятия "ответ" на сообщения
т.е. тут один воркфоу и разрывается

Ayrat
19.07.2018
06:37:28
ну так мейлбоксы это и решают
послал туда запрос, тебе пришёл ответ (возможно)

Pavel
19.07.2018
06:38:31
ну вот мне потребовалось создать запрос удалённому узлу, я написал в сокет, а в это время мне в сокет, который я слушаю, могут писать другие узлы

Ayrat
19.07.2018
06:38:53
ты хочешь получать от сервера ченел для ответа, сообщение в ящик с ответом или промиз ответа?

Pavel
19.07.2018
06:39:26
между удалёнными узлами — сообщение в ящик (и каждая пара реквест-респонс пронумерована одинаковым guid типа conversationId)
но локальному клиенту надо отдать промис на ответ
т.е. получается, что локальный клиент вызывает функцию, которая генерит гуид для новой беседы, создаёт реквест к удалённому узлу и ожидает когда-нибудь получить от него в свой ящик ответ с таким же гуидом. как только она его получает — она должна заполнить проимс пришедшим значением

Ayrat
19.07.2018
06:42:42
ну я вижу так
если клиент и обёртка на клиенте для общения с сервером по UDP
сигнатура обёртки чот типа Request -> Async<Response>
обёртка - асинхронный блок, который делает чот типа
async {
do! socket.send data
let rec listenLoop = async {
let! incoming = socket.listen()
if incoming = validData then return incoming
else return! listenLoop
}
return! listenLoop
}

Pavel
19.07.2018
06:44:44
в таком случае на каждый реквест, по приходу нового сообщения, будет заниматься тред и смотреть что там пришло

Google

Ayrat
19.07.2018
06:45:09
ну это не так работает прям)
асинк тоже через тредпул работает, как и таски

Pavel
19.07.2018
06:45:48
условно есть 1000 активных запросов — приходит что-то в сокет — 1000 раз листнеры проверят это сообщение и только один поймёт, что гуид совпадает и это ответ на именно его запрос
ну это-то понятно, просто все 1000 листнеров отработают

Ayrat
19.07.2018
06:46:27
а, я понял

Pavel
19.07.2018
06:46:55
я же запоминаю в хешмапу все активные запросы по guid -> responseProcessor и по приходу сообщения в совкет отдаю только одному обработчику ответа
ну и этот словарь пробрасывается в следующую итерацию мейлбокса
поэтому тут и возникает разрыв воркфлоу
+ в моём случае ответ на один запрос может сильно повлиять на все остальные активные запросы (например, отменить их)


Ayrat
19.07.2018
06:51:23
псевдокод одного актора листенера
let requestMap = Dictionary<_,_>
let actor =
mailbox {
match! mailbox.Receive() with
| AddNewListener (guid, responseChannel) -> requestMap.Add (guid, responseChannel)
| IncomingData data ->
let respChannel = requestMap.[data.Id]
do! respChannel.Send data.Payload
return! actorLoop
}
let listenLoop() = async {
let! data = socket.Listen()
do! actor.Send (IncomingData data)
return! listenLoop()
}
ну чот тип того
я не помню точно как агенты в F# пишутся, но смысл думаю понятен
делаем один луп, который слушает и кидает в мейлбокс данные.
Есть собсно мейлбокс который принимает только запросы клиентов и приходящие данные из сокета.
Запросы клиентов регистрируются с айди запроса и ченелом ответа, приходящие данные мапятся в нужный канал ответа

Pavel
19.07.2018
06:53:09
всё, я тупой
я, похоже, понял

Ayrat
19.07.2018
06:53:18
ну там надо ещё удалять из дикшнари, да

Pavel
19.07.2018
06:53:25
забыл про postAndReplyAsync

Ayrat
19.07.2018
06:53:30
я не до псевдокодил все нюансы

Pavel
19.07.2018
06:53:33
спасибо :D

Ayrat
19.07.2018
06:53:33
дада, он самы1й

Google

Pavel
19.07.2018
06:54:11
самый прикол, что я его активно использую в других местах, а тут зацепился за TaskCompletionSource и всё

Roman
19.07.2018
07:01:47
Всем привет.
Есть кто-то, кто активно использует fable?

Vasily
19.07.2018
07:08:43
Чет мне вдруг подумалось, что мейлбоксы можно сопрячь с акторами
Используя не ask
А PostAndReplyAsync

Ayrat
19.07.2018
07:09:26
ну началось)))

Vasily
19.07.2018
07:09:39
С точки зрения актора операция будет неблокирующей
Но будет торчать мутабельный стейт снаружи

Ayrat
19.07.2018
07:11:05
с точки зрения обработки мейлбокса она должна быть неблокирующей

Vasily
19.07.2018
07:11:20
Ну она и будет

Ayrat
19.07.2018
07:11:27
и да, будет с ченелами

Vasily
19.07.2018
07:11:47
Ты ж асинк наружу возвращаешь
Ещё вариант перед каждым изменением стейта актора вызывать внешний 'a->unit
Хотя это будет блокирующая операция
Можно асинк

Klei
19.07.2018
07:15:14

Ayrat
19.07.2018
07:16:06
Можно асинк
я пока всё ещё не понимаю зачем совмещать мейлбоксы и акторов, если это по сути одно и то же)

Vasily
19.07.2018
07:16:46
Или действительно создать суперактора с аском

Ayrat
19.07.2018
07:17:14
ну так акторы тоже могут эту роль выполнять. TaskCompletionSource это и есть по смыслу ченел ответа

Google

Vasily
19.07.2018
07:17:44
Как ты его вытащишь?

Ayrat
19.07.2018
07:18:24
на клиенте, который создаёт запрос, создаём TCS, передаём куда надо с запросом. Где надо когда-то заполняется TCS
на клиенте ожидаем появления результата в нашем TCS
очевидно эта штука не сериализуется, поэтому только ин-процесс это работает)

Vasily
19.07.2018
07:19:10
Ну это понятно

Ayrat
19.07.2018
07:20:17
ну я часто ченелы использую в гопачке, они там вообще для всего используются. для прокидываная NACK, для ответов, для запросов, для всего подряд короче)

Vasily
19.07.2018
07:23:58
А в акке как?

Ayrat
19.07.2018
07:24:46
PipeTo норм
Стартуешь таск в актора, его результат кидаешь кому-то в мейлбокс сразу через пайпту. Это на фоне будет крутиться

Vasily
19.07.2018
07:26:23
PipeTo это вроде про передачу в актор

Ayrat
19.07.2018
07:26:47
Ну да.

Vasily
19.07.2018
07:27:25
А тут задача обратная
Получить ответ во внешний мир

Ayrat
19.07.2018
07:27:54
Ну тогда тебе надо работать через TCS, как аналог ченелов в TPL
Если прям без асов хочешь. Но я так не делал)

Roman
19.07.2018
08:02:00

Klei
19.07.2018
10:23:24

Roman
19.07.2018
10:41:57

Dmitry
19.07.2018
12:01:07
А помогите с пятым FAKE

Roman
19.07.2018
12:02:04

Google

Dmitry
19.07.2018
12:02:31
Если раньше писалось
Target "Restore" (fun _ ->
DotNetCli.Restore (fun p -> {p with WorkingDir = appPath})
)
то теперь
Target.create "Restore" (fun _ ->
DotNet.restore и тут как-то DotNet.RestoreOptions передать?
)
я что-то в сигнатурах запутался

Roman
19.07.2018
12:04:35
Оу, я хз пока.

Ayrat
19.07.2018
12:05:18

Летучая
19.07.2018
12:14:04
Хм, есть ли эксперты по fable в чате? Почему, если часто вызывать одну и ту же функцию (нет, она не рекурсивная), происходит падение с Maximum call stack size exceeded? То есть если сделать window.setInterval(loop, 20), рано или поздно loop: unit -> unit всегда начнёт выбрасывать исключения такого характера.

Ayrat
19.07.2018
12:17:59
а в js есть tailcall рекурсия?

Pavel
19.07.2018
12:18:16

Ayrat
19.07.2018
12:18:34
тогда есть мнение, что не стоит делать рекурсивные вызовы в js :D

евроневидимка
19.07.2018
12:18:51
ну так соптимизировать же можно даже в жс
через вайл

Летучая
19.07.2018
12:21:20
Ну, setInterval — это не рекурсия же. Это вызов одной и той же функции через вайл или типа того. Рекурсивных вызовов там вообще нет.

Artem
19.07.2018
12:24:44
могу доклад по теме кинуть
там когда вызываешь асинхронно методы
там всё равно будет стек вызовов и он их по очереди обрабатывает
как-то так
ща
точнее
https://www.youtube.com/watch?v=8aGhZQkoFbQ
@worldbeater

Летучая
19.07.2018
12:32:54
А если вкратце, то это даже с setTimeout/setInterval можно стек вызовов забить? Как тогда игори-то писать (да и на чистом JS у меня не было таких проблем никогда)

Artem
19.07.2018
12:36:08
ну там есть же ещё очередь коллбеков, в которую сеттаймаут/сетинтервал пишет. мб её забиваешь за это время?
(но я хз, мне просто чёт по твоему вопросу именно этот доклад вспомнился)