异步响应中调用异步http请求,centos下无法响应
代码如下
std::shared_ptr<std::string> RequestPbf(const std::string& url, const std::string& path, const std::string& body, HttpContextPtr ctx)
{
HttpRequestPtr req(new HttpRequest);
req->method = HTTP_POST;
req->url = url + path;
req->headers["Connection"] = "keep-alive";
req->body = body;
req->timeout = 10;
http_client_send_async(req, [ctx](const HttpResponsePtr& resp) {
printf("test_http_async_client response thread tid=%ld\n", hv_gettid());
if (resp == NULL) {
//...
return;
}
else {
printf("%d %s\r\n", resp->status_code, resp->status_message());
printf("%s\n", resp->body.c_str());
}
ctx->send(resp->body, APPLICATION_OCTET_STREAM); //<<------------------
});
}
router.GET("/test", [](const HttpContextPtr& ctx) {
PLOG_DEBUG("----");
hv::async([ctx]() {
//...
RequestPbf(ctx);
});
return 0;
});
在windows下,能接收客户端请求,并正常返回,centos下,多进程方式,无法接收请求,PLOG_DEBUG("----");都没有输出,不知道是什么原因?是否还是和线程池有关?
可以看下logs目录下的日志里有访问记录没
另外http_client_send_async本身就是在另外线程异步请求,没必要再使用hv::async包裹了
logs目录下没有日志,而且其他使用同步的接口也全都不能响应了,chrome请求返回ERR_EMPTY_RESPONSE错误
//以下接口也不能响应
router.GET("/mvt/dataset/tilejson/{id}", [](HttpRequest* req, HttpResponse* resp) {
//...
}
你说的多进程是指设置了HtttpServer的worker_processes吗,你可以先试下examples/httpd示例吧,就是多进程模型运行的。
make
bin/httpd -d
ps aux | grep httpd
bin/curl -v 127.0.0.1:8080/echo -d 'hello'
不好意思,我对比了下httpd的代码,发现我没加log,加上后log里输出以下错误
2022-09-21 16:34:37.402 INFO worker_thread pid=20444 tid=20444 [hmain.c:567:worker_thread]
2022-09-21 16:34:37.402 INFO worker_thread pid=20444 tid=20467 [hmain.c:567:worker_thread]
2022-09-21 16:34:37.554 INFO pid=18334 recv signo=17 [hmain.c:372:signal_handler]
2022-09-21 16:34:37.554 WARN proc stop/waiting, pid=20395 status=11 [hmain.c:391:signal_handler]
2022-09-21 16:34:37.554 ERROR proc crash, pid=20395 spawn_cnt=3 run_time=0s [hmain.c:402:signal_handler]
2022-09-21 16:34:37.558 INFO pid=18334 recv signo=17 [hmain.c:372:signal_handler]
2022-09-21 16:34:37.558 WARN proc stop/waiting, pid=20408 status=11 [hmain.c:391:signal_handler]
2022-09-21 16:34:37.558 ERROR proc crash, pid=20408 spawn_cnt=3 run_time=0s [hmain.c:402:signal_handler]
2022-09-21 16:34:37.563 INFO pid=18334 recv signo=17 [hmain.c:372:signal_handler]
2022-09-21 16:34:37.563 WARN proc stop/waiting, pid=20444 status=11 [hmain.c:391:signal_handler]
以下是我主函数部分的代码,实在看不出和httpd流程上有什么区别
using namespace std;
hv::HttpServer g_http_server;
hv::HttpService g_http_service;
void print_version() {
printf("%s version %s\n", g_main_ctx.program_name, "6.0");
}
void print_help() {
//printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
//printf("Options:\n%s\n", detail_options);
}
bool ParseConfig(std::string conf_path)
{
//初始化所有配置文件路径
//InitSettingFileGroup(conf_path.c_str());
//InitEnvir();
hlog_set_file("/logs/seogcserver.log"/*g_main_ctx.logfile*/);
hlog_set_level_by_str("INFO"/*str.c_str()*/);
hlog_set_max_filesize_by_str("64M"/*str.c_str()*/);
hlog_set_remain_days(atoi("3"/*str.c_str()*/));
hlogi("%s version: %s", g_main_ctx.program_name, hv_compile_version());
hlog_fsync();
auto& setting = Singleton<Setting>::Instance();
// worker_processes
int worker_processes = setting.worker_processes();
if (worker_processes == 0) {
worker_processes = GetCPUCoreNum();
}
g_http_server.worker_processes = LIMIT(0, worker_processes, MAXNUM_WORKER_PROCESSES);
auto worker_threads = GetCPUCoreNum();
g_http_server.worker_threads = LIMIT(0, worker_threads, 64);
g_http_server.port = 30001; // setting.port();
g_http_service.document_root = "html";
g_http_service.home_page = "index.html";
g_http_service.index_of = "downloads";
// https_port
if (HV_WITH_SSL) {
g_http_server.https_port = setting.https_port();
}
if (g_http_server.port == 0 && g_http_server.https_port == 0) {
PLOG_ERR("Please config listen port!");
return false;
}
return true;
}
void main_exit() {
}
static void on_reload(void* userdata) {
//hlogi("reload confile [%s]", g_main_ctx.confile);
ParseConfig(g_main_ctx.confile);
}
int main(int argc, char** argv)
{
cmdline::parser a;
a.add<string>("conf", 'c', "config path", false, se::GetModulePath());
a.add<string>("signal", 's', "signal", false, "");
a.add("version", 'v', "version");
a.add("help", 'h', "help");
a.add("daemon", 'd', "daemon");
a.parse_check(argc, argv);
auto conf_path = a.get<string>("conf");
if (conf_path.empty()) {
conf_path = se::GetModulePath();
se::NormalizePath(conf_path);
}
// g_main_ctx
main_ctx_init(argc, argv);
// help
if (a.exist("help")) {
print_help();
exit(EXIT_SUCCESS);
}
// version
if (a.exist("version")) {
print_version();
exit(EXIT_SUCCESS);
}
atexit(main_exit);
// parse_confile
strncpy(g_main_ctx.confile, conf_path.c_str(), sizeof(g_main_ctx.confile));
if (!ParseConfig(g_main_ctx.confile)) {
PLOG_ERR("failed to parse config");
return -1;
}
// signal
signal_init(on_reload);
auto signal = a.get<string>("signal");
if (!signal.empty()) {
signal_handle(signal.c_str());
}
#ifdef OS_UNIX
// daemon
if (a.exist("daemon")) {
// nochdir, noclose
int ret = daemon(1, 1);
if (ret != 0) {
PLOG_ERR("daemon error: %d", ret);
exit(-10);
}
}
#endif
// pidfile
create_pidfile();
// http_server
Router::Register(g_http_service);
g_http_server.registerHttpService(&g_http_service);
g_http_server.run(false);
while (getchar() != '\n') {};
return 0;
}
如果请求频繁,程序就coredump,输出
2022-09-21 17:00:27.094 ERROR proc crash, pid=2800 spawn_cnt=3 run_time=1s [hmain.c:402:signal_handler]
否则只会输出
2022-09-21 17:00:26.926 WARN proc stop/waiting, pid=1799 status=11 [hmain.c:391:signal_handler]
如果请求频繁,程序就coredump,输出
2022-09-21 17:00:27.094 ERROR proc crash, pid=2800 spawn_cnt=3 run_time=1s [hmain.c:402:signal_handler]否则只会输出
2022-09-21 17:00:26.926 WARN proc stop/waiting, pid=1799 status=11 [hmain.c:391:signal_handler]
没看出什么问题,只看到你即使用了worker_processes多进程,又使用了worker_threads多线程,所以总的IO线程数是worker_processes * worker_threads 既然有coredump,抓下来gdb bt打印下堆栈就知道了
似乎是和sogou的workflow库有冲突,一模一样的流程请求,只要编译代码target_link_libraries中引入 libworkflow.a,ssl,crypto后,请求就会崩溃,去掉后编译生成,就能正常响应。这是啥原因?
Stack trace (most recent call last) in thread 16607:
#13 Object "[0xffffffffffffffff]", at 0xffffffffffffffff, in
#12 Object "/lib64/libc.so.6", at 0x7f1d89328b0c, in clone
#11 Object "/lib64/libpthread.so.0", at 0x7f1d89f1dea4, in
#10 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d0fd310, in
#9 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d138007, in
#8 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d10179e, in hloop_run
#7 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d104ad7, in
#6 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d1035fd, in hio_handle_read
#5 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d102e5b, in hio_read_cb
#4 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d138858, in
#3 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d13b844, in HttpHandler::Init(int, hio_s*)
#2 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d113b18, in HttpParser::New(http_session_type, http_version)
#1 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f1d8d113fa2, in Http1Parser::Http1Parser(http_session_type)
#0 Object "tpserver: worker process", at 0x7696f2, in http_parser_init
Segmentation fault (Address not mapped to object [0x2])
看你的崩溃信息是在http_parser_init 这个函数在libhv里是用的开源的没有改动的http_parser,但是workflow里是自己魔改过,如果静态链接workflow库,导致原本应该使用hv动态库里的http_parser,但是却使用了workflow里的,导致崩溃。 解决方法可以动态链接workflow,或者给其中一个库源码里的http_parser加个前缀改名
改连接动态库libworkflow.so.0.10.3,还是会崩,堆栈
test_http_async_client response thread tid=8141
request failed!
Stack trace (most recent call last) in thread 8141:
#12 Object "[0xffffffffffffffff]", at 0xffffffffffffffff, in
#11 Object "/lib64/libc.so.6", at 0x7f0cc44f0b0c, in clone
#10 Object "/lib64/libpthread.so.0", at 0x7f0cc50e5ea4, in
#9 Object "/usr/sevs/lib/libstdc++.so.6", at 0x7f0cc4da928f, in
#8 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f0cc85c80ef, in hv::EventLoopThread::loop_thread(std::function<int ()> const&, std::function<int ()> const&)
#7 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f0cc858579e, in hloop_run
#6 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f0cc85889e6, in
#5 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f0cc8588652, in
#4 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f0cc8588271, in hio_close
#3 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f0cc85c95a7, in
#2 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f0cc85cb9f4, in hv::HttpClientContext::callback()
#1 Object "tpserver: worker process", at 0x5652e7, in
#0 Object "/usr/sevs/lib/libstdc++.so.6", at 0x7f0cc4e0f172, in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
Segmentation fault (Address not mapped to object [0x60])
但如果直接返回一个响应是可以的
std::shared_ptr<std::string> RequestPbf1(HttpContextPtr ctx)
{
//ctx->send("test"); <<---直接返回这个是可以的
HttpRequestPtr req(new HttpRequest);
req->method = HTTP_POST;
req->url = "http://192.168.1.104:30000/sevs/api/vec/pbf";
req->headers["Connection"] = "keep-alive";
req->body = R"({"extent":4096,"layer_list":[{"avoidance":true,"bbox":{"max_x":-77.003173828125,"max_y":38.91668153637507,"min_x":-77.01416015625,"min_y":38.908132995967044},"dataset_id":"6962309382061297664","dataset_ver":0,"field_list":["name"],"filter":"","layer_name":"","size":1}],"level":15,"x":9374,"y":12533})";
req->timeout = 10;
http_client_send_async(req, [ctx](const HttpResponsePtr& resp) {
printf("test_http_async_client response thread tid=%ld\n", hv_gettid());
if (resp == NULL) {
printf("request failed!\n");
}
else {
printf("%d %s\r\n", resp->status_code, resp->status_message());
printf("%s\n", resp->body.c_str());
}
ctx->send(resp->body, APPLICATION_OCTET_STREAM);
});
return nullptr;
}
打印出request failed!,说明resp为空,你后面还使用resp->body,空指针崩溃了
感谢回复,那个后端服务不知什么时候被停了。 现在我用libhv的http异步处理可以了,但用workflow的http_task还是会崩,不知道哪里还有冲突
//这个可以
void RequestPbf(const std::string& path, const std::string& body, HttpContextPtr ctx)
{
auto& se = Singleton<Setting>::Instance().seserver_;
auto url = se::FormatStr("http://%s:%d%s", se.host_.c_str(), se.port_, path.c_str());
HttpRequestPtr req(new HttpRequest);
req->method = HTTP_POST;
req->url = url;
req->headers["Connection"] = "keep-alive";
req->body = body;
req->timeout = 600;
http_client_send_async(req, [ctx](const HttpResponsePtr& resp) {
if (!resp) {
ctx->setStatus(HTTP_STATUS_INTERNAL_SERVER_ERROR);
ctx->send("", APPLICATION_OCTET_STREAM);
return;
}
ctx->send(resp->body, APPLICATION_OCTET_STREAM);
});
}
//使用workflow的httptask,在windows下运行正常,centos下崩溃
void HttpCallBack(WFHttpTask* task)
{
using namespace protocol;
auto context = ((Context*)task->user_data);
auto ctx = context->ctx_;
bool ret = false;
defer(
if (!ret) {
ctx->setStatus(HTTP_STATUS_INTERNAL_SERVER_ERROR);
ctx->send("error");
}
delete context;
);
protocol::HttpRequest* req = task->get_req();
protocol::HttpResponse* resp = task->get_resp();
int state = task->get_state();
int error = task->get_error();
switch (state)
{
case WFT_STATE_SUCCESS:
break;
case WFT_STATE_SYS_ERROR:
PLOG_ERR("system error: %s", strerror(error));
break;
case WFT_STATE_DNS_ERROR:
PLOG_ERR("DNS error: %s", gai_strerror(error));
break;
case WFT_STATE_SSL_ERROR:
PLOG_ERR("SSL error: %d", error);
break;
case WFT_STATE_TASK_ERROR:
PLOG_ERR("Task error: %d", error);
break;
default:
PLOG_ERR("error: %s", strerror(error));
break;
}
if (state != WFT_STATE_SUCCESS){
return;
}
const void* body;
size_t body_len;
resp->get_parsed_body(&body, &body_len);
if ( body && body_len > 0 ){
auto data = std::make_shared<std::string>((char*)body, body_len);
ctx->send(*data, APPLICATION_OCTET_STREAM);
auto cache_manager = GetCacheManager();
if ( cache_manager){
cache_manager->AddTile(context->cache_key_, context->lvl_, context->x_, context->y_, context->mode_, data);
PLOG_DEBUG("add tile to cache: %d/%d/%d, cache_key: %s", context->lvl_, context->x_, context->y_, context->cache_key_.c_str());
}
}
ret = true;
}
void RequestPbf(const std::string& path, const std::string& body, Context* context)
{
#define REDIRECT_MAX 5
#define RETRY_MAX 2
auto& se = Singleton<Setting>::Instance().seserver_;
auto url = se::FormatStr("http://%s:%d%s", se.host_.c_str(), se.port_, path.c_str());
auto task = WFTaskFactory::create_http_task(url, REDIRECT_MAX, RETRY_MAX,
HttpCallBack);
task->user_data = context;
protocol::HttpRequest* req = task->get_req();
req->set_method("POST");
req->add_header_pair("Accept", "*/*");
req->add_header_pair("User-Agent", "Wget/1.14 (linux-gnu)");
req->add_header_pair("Connection", "close");
req->add_header_pair("Content-Type", "application/json");
req->append_output_body(body.c_str(), body.size());
task->start();
}
堆栈
Stack trace (most recent call last) in thread 25323:
#17 Object "[0xffffffffffffffff]", at 0xffffffffffffffff, in
#16 Object "/lib64/libc.so.6", at 0x7f251bab2b0c, in clone
#15 Object "/lib64/libpthread.so.0", at 0x7f251c6a7ea4, in
#14 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb43310, in
#13 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb7e007, in
#12 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb4779e, in hloop_run
#11 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb4aad7, in
#10 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb495fd, in hio_handle_read
#9 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb48e5b, in hio_read_cb
#8 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb7f46e, in
#7 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb78903, in HttpHandler::HandleHttpRequest()
#6 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb7833b, in HttpHandler::defaultRequestHandler()
#5 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb7790a, in HttpHandler::invokeHttpHandler(http_handler const*)
#4 Object "tpserver: worker process", at 0x564fe4, in
#3 Object "tpserver: worker process", at 0x5340bf, in GetDatasetPbf(unsigned long, unsigned int, unsigned int, unsigned int, TileMode, bool, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, bool&, std::shared_ptr<hv::HttpContext> const&)
#2 Object "tpserver: worker process", at 0x52f571, in RequestPbf(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Context*)
#1 Object "/usr/sevs/lib/libworkflow.so.0", at 0x7f251d8b674a, in WFTaskFactory::create_http_task(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int, int, std::function<void (WFNetworkTask<protocol::HttpRequest, protocol::HttpResponse>*)>)
#0 Object "/home/hyj/v6/tpserver/../thirdparty/lib/linux/x86_64/libhv.so", at 0x7f251fb57140, in http_parser_init