Closed pengweichu closed 3 years ago
Uhm... Data are consumed and likely destroyed by when the callback is invoked. However, you've an user data field on all handles. You can probably attach them there to reuse the sane information in case of errors.
Uhm... Data are consumed and likely destroyed by when the callback is invoked. However, you've an user data field on all handles. You can probably attach them there to reuse the sane information in case of errors.
I would like to have the user data for every write, seems not to support it now. Thanks
Hello @pengweichu, I'm not a libuv
super-expert.
AFAIK, the uv_write performs a copy and invalidate your data.
Cannot understand if you can recover this, I think not.
You should take this "sending" message somewhere suitable (I suggest not global ;)) and remove once sent.
@pengweichu I recall that you can use tryWrite instead, to know if you are not able to send data and easier manage the failure.
Thanks all, I'm going to use the ASIO.
This seems to be a constant pain-point when using this library and it is essentially caused by having all errors published to ErrorEvent. It'd be nice to be able to easily determine the source of an error so the corresponding operation can be retried.
For example, if we had uvw::WriteErrorEvent
, this write-specific error can contain the data that the user tried to write.
The v3
branch already contains a lot of changes in this regard.
I'm more than willing to refine it further but please give it a look and try to formulate a request in this regard.
CC @stefanofiorentino side question: what if we merged the branch upstream next week?
@skypjack Do you have an example of how to perform write()
retries with the v3 api?
I ended up modifying the write method in uvw to run a callback in the listener once write completes/fails. The callback then fires whatever events I need to be fired.
CC @stefanofiorentino side question: what if we merged the branch upstream next week?
@skypjack up to me it's ok to merge. Let's remember we'll break several projects pointing to master's HEAD, though.
For anyone who later stumbles across this issue, here's the modification I made to the write()
method in the stream.hpp
(or stream.h
) file.
void write(char *data, unsigned int len, std::function<void(void)> done) {
auto req = this->loop().template resource<details::WriteReq>(
std::unique_ptr < char[], details::WriteReq::Deleter > {
data, [](char *) {}
}, len);
auto listener = [ptr = this->shared_from_this(), done](const auto &event, const auto &) {
ptr->publish(event);
done();
};
req->template once<ErrorEvent>(listener);
req->template once<WriteEvent>(listener);
req->write(this->template get<uv_stream_t>());
}
Of course, one can have a separate listener for WriteEvent
and ErrorEvent
and only run the done()
callback when a failure occurs (i.e. the ErrorEvent
listener). The done()
callback then triggers the retry.
To spell it all out, the retry logic should look like this.
void write(char *data, unsigned int len, std::function<void(char *, unsigned int)> retry) {
auto req = this->loop().template resource<details::WriteReq>(
std::unique_ptr < char[], details::WriteReq::Deleter > {
data, [](char *) {}
}, len);
auto writeListener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
ptr->publish(event);
};
auto errorListener = [ptr = this->shared_from_this(), retry](const auto &event, const auto &) {
ptr->publish(event);
retry(data, len);
};
req->template once<ErrorEvent>(errorListener);
req->template once<WriteEvent>(writeListener);
req->write(this->template get<uv_stream_t>());
}
If the write is failed, the ErrorEvent will be triggered, but I would like to resend send that data again, so how can get the data in the ErrorEvent?
Can I set any id with the write function then that id will be callback in the ErrorEvent or WriteEvent?
Thanks