libhv icon indicating copy to clipboard operation
libhv copied to clipboard

异步响应中调用异步http请求,centos下无法响应

Open cmoth150415 opened this issue 3 years ago • 2 comments

代码如下

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("----");都没有输出,不知道是什么原因?是否还是和线程池有关?

cmoth150415 avatar Sep 19 '22 11:09 cmoth150415

可以看下logs目录下的日志里有访问记录没

ithewei avatar Sep 19 '22 14:09 ithewei

另外http_client_send_async本身就是在另外线程异步请求,没必要再使用hv::async包裹了

ithewei avatar Sep 19 '22 14:09 ithewei

logs目录下没有日志,而且其他使用同步的接口也全都不能响应了,chrome请求返回ERR_EMPTY_RESPONSE错误

//以下接口也不能响应
router.GET("/mvt/dataset/tilejson/{id}", [](HttpRequest* req, HttpResponse* resp) {
//...
}

cmoth150415 avatar Sep 21 '22 02:09 cmoth150415

你说的多进程是指设置了HtttpServer的worker_processes吗,你可以先试下examples/httpd示例吧,就是多进程模型运行的。

make
bin/httpd -d
ps aux | grep httpd
bin/curl -v 127.0.0.1:8080/echo -d 'hello'

ithewei avatar Sep 21 '22 02:09 ithewei

不好意思,我对比了下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]

cmoth150415 avatar Sep 21 '22 08:09 cmoth150415

以下是我主函数部分的代码,实在看不出和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;
}

cmoth150415 avatar Sep 21 '22 08:09 cmoth150415

如果请求频繁,程序就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]

cmoth150415 avatar Sep 21 '22 09:09 cmoth150415

如果请求频繁,程序就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打印下堆栈就知道了

ithewei avatar Sep 21 '22 11:09 ithewei

似乎是和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])

cmoth150415 avatar Sep 22 '22 03:09 cmoth150415

看你的崩溃信息是在http_parser_init 这个函数在libhv里是用的开源的没有改动的http_parser,但是workflow里是自己魔改过,如果静态链接workflow库,导致原本应该使用hv动态库里的http_parser,但是却使用了workflow里的,导致崩溃。 解决方法可以动态链接workflow,或者给其中一个库源码里的http_parser加个前缀改名

ithewei avatar Sep 22 '22 04:09 ithewei

改连接动态库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])


cmoth150415 avatar Sep 23 '22 02:09 cmoth150415

但如果直接返回一个响应是可以的

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;
}

cmoth150415 avatar Sep 23 '22 02:09 cmoth150415

打印出request failed!,说明resp为空,你后面还使用resp->body,空指针崩溃了

ithewei avatar Sep 23 '22 05:09 ithewei

感谢回复,那个后端服务不知什么时候被停了。 现在我用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

cmoth150415 avatar Sep 23 '22 07:09 cmoth150415