NOVA示例教程¶

  • 编写nova服务thrift文件
  • 生成nova存根代码, 发布到仓库
  • tcp(nova服务端)项目 与 http(nova客户端)项目 composer.json 分别添加nova存根代码 依赖
  • tcp(nova服务端)项目 实现 nova 服务接口, 配置发布服务
  • http(nova客户端)项目 配置直接tcp-server,通过 nova存根代码调用nova服务

编写nova服务thrift文件¶

thrift 结构

  1. .
  2. └── thrifts
  3. ├── entity
  4. ├── BaseStruct.thrift
  5. ├── ErrorLevel.thrift
  6. └── MixedStruct.thrift
  7. ├── exception
  8. └── DemoServiceException.thrift
  9. └── service
  10. └── DemoService.thrift

BaseStruct.thrift

  1. namespace nova com.yourcompany.demo.entity
  2.  
  3. include 'ErrorLevel.thrift'
  4.  
  5. struct BaseStruct {
  6. 1:optional bool propBool,
  7. 2:optional byte propByte,
  8. 3:optional i16 propI16,
  9. 4:optional i32 propI32,
  10. 5:optional i64 propI64,
  11. 6:optional double propDouble,
  12. 7:optional string propString,
  13. 8:optional ErrorLevel.ErrorLevel errorLevel
  14. }

ErrorLevel.thrift

  1. namespace nova com.yourcompany.demo.entity
  2.  
  3. enum ErrorLevel {
  4. DEBUG = 1,
  5. INFO = 2,
  6. WARN = 3,
  7. ERROR = 4
  8. }

MixedStruct.thrift

  1. namespace nova com.yourcompany.demo.entity
  2.  
  3. include 'BaseStruct.thrift'
  4.  
  5. struct MixedStruct {
  6. 1:optional string propString,
  7. 2:optional BaseStruct.BaseStruct baseStruct,
  8. 3:optional list<BaseStruct.BaseStruct> propList,
  9. 4:optional set<BaseStruct.BaseStruct> propSet,
  10. 5:optional map<string, BaseStruct.BaseStruct> propMap
  11. }

DemoServiceException.thrift

  1. namespace nova com.yourcompany.demo.exception
  2.  
  3. exception DemoServiceException {
  4. 1: string message
  5. 2: i32 code
  6. }

DemoService.thrift

  1. namespace nova com.yourcompany.demo.service
  2.  
  3. include '../entity/ErrorLevel.thrift'
  4. include '../entity/BaseStruct.thrift'
  5. include '../entity/MixedStruct.thrift'
  6. include '../exception/DemoServiceException.thrift'
  7.  
  8. service DemoService {
  9. void throwException() throws (1:DemoServiceException.DemoServiceException e);
  10.  
  11. void returnVoid();
  12.  
  13. bool returnBool();
  14. i32 returnI32();
  15. double returnDouble();
  16. string returnString();
  17. ErrorLevel.ErrorLevel returnEnum();
  18.  
  19.  
  20. BaseStruct.BaseStruct returnBaseStruct();
  21. MixedStruct.MixedStruct returnMixedStruct();
  22. list<BaseStruct.BaseStruct> returnList();
  23. set<BaseStruct.BaseStruct> returnSet();
  24. map<string, BaseStruct.BaseStruct> returnMap();
  25.  
  26. void paraBaseNoReturn(1:string paraString, 2:ErrorLevel.ErrorLevel errorLevel);
  27.  
  28. void paraMixedNoReturn (
  29. 1:bool paraBool,
  30. 2:i32 paraI32,
  31. 3:double paraDouble,
  32. 4:string paraString,
  33. 5:BaseStruct.BaseStruct baseStruct,
  34. 6:list<BaseStruct.BaseStruct> returnList,
  35. 7:set<BaseStruct.BaseStruct> returnSet,
  36. 8:map<string, BaseStruct.BaseStruct> returnMap,
  37. 9:ErrorLevel.ErrorLevel errorLevel
  38. );
  39.  
  40. map<string, BaseStruct.BaseStruct> complexMethod(
  41. 1:bool paraBool,
  42. 2:i32 paraI32,
  43. 3:double paraDouble,
  44. 4:string paraString,
  45. 5:BaseStruct.BaseStruct baseStruct,
  46. 6:list<BaseStruct.BaseStruct> returnList,
  47. 7:set<BaseStruct.BaseStruct> returnSet,
  48. 8:map<string, BaseStruct.BaseStruct> returnMap,
  49. 9:ErrorLevel.ErrorLevel errorLevel
  50. )
  51. }

生成nova存根代码, 发布到仓库¶

下载或者编译zan-thrift工具¶

  1. cd thrifts
  2. zan-thrift --gen php # 执行工具生成存根代码

执行结果:

  1. Processing: .../nova-demo/thrifts/entity/BaseStruct.thrift
  2. Processing: .../nova-demo/thrifts/entity/ErrorLevel.thrift
  3. Processing: .../nova-demo/thrifts/entity/MixedStruct.thrift
  4. Processing: .../nova-demo/thrifts/exception/DemoServiceException.thrift
  5. Processing: .../nova-demo/thrifts/service/DemoService.thrift

tree

  1. ├── sdk
  2. └── gen-php
  3. ├── Entity
  4. ├── BaseStruct.php
  5. ├── ErrorLevel.php
  6. └── MixedStruct.php
  7. ├── Exception
  8. └── DemoServiceException.php
  9. ├── Interfaces
  10. └── DemoService.php
  11. ├── Service
  12. └── DemoService.php
  13. └── Servicespecification
  14. └── DemoService.php

编写composer.json¶

  1. {
  2. "name": "nova-service/nova-demo",
  3. "repositories": [
  4. ],
  5. "require": {
  6. "packaged/thrift": "0.9.2.1"
  7. },
  8. "autoload": {
  9. "psr-4": {
  10. "Com\\Yourcompany\\Demo\\": "sdk/gen-php"
  11. },
  12. "classmap": []
  13. }
  14. }

注意 psr-4 命名空间要与thrift文件命名空间一致,遵守com.:math:{company}.{module}[…]规范

将生成的存根代码push到git仓库

tcp(nova服务端)项目 与 http(nova客户端)项目 composer.json 分别添加 nova存根代码 依赖¶

  1. {
  2. ...
  3. "repositories": {
  4. # 这里因为测试demo的缘故,存根代码放在本地,通过路径引用,composer会在vendor中建立软连接
  5. # 正常项目引用独立的nova-service package
  6. {
  7. "type": "path",
  8. "url": "nova-sdk/nova-demo/",
  9. "options": {
  10. "symlink": true
  11. }
  12. }
  13. },
  14. "require": {
  15. ...
  16. # require 添加
  17. "nova-service/nova-demo": "*"
  18. }
  19. ...
  20. }

tcp(nova服务端)项目 实现 nova 服务接口, 配置发布服务¶

tcp-demo/src/Service/DemoService.php

  1. <?php
  2.  
  3. namespace Com\Youzan\TcpDemo\Service;
  4.  
  5.  
  6. use Com\Yourcompany\Demo\Entity\BaseStruct;
  7. use Com\Yourcompany\Demo\Entity\ErrorLevel;
  8. use Com\Yourcompany\Demo\Entity\MixedStruct;
  9. use Com\Yourcompany\Demo\Exception\DemoServiceException;
  10.  
  11. class DemoService implements \Com\Yourcompany\Demo\Interfaces\DemoService
  12. {
  13.  
  14.  
  15. public function returnBool()
  16. {
  17. yield true;
  18. }
  19.  
  20. public function returnI32()
  21. {
  22. yield rand() % 1024;
  23. }
  24.  
  25. public function returnDouble()
  26. {
  27. yield rand(1, 100) / (double)100;
  28. }
  29.  
  30. public function returnString()
  31. {
  32. yield str_repeat('a', rand(1, 20));
  33. }
  34.  
  35. public function returnEnum()
  36. {
  37. yield ErrorLevel::INFO;
  38. }
  39.  
  40. ......
  41. }

配置nova服务发布

tcp-demo/resource/config/${env}/nova.php

  1. <?php
  2.  
  3. return [
  4. // 发布服务
  5. "novaApi" => [
  6. "path" => "vendor/nova-service/nova-demo/sdk/gen-php",
  7. // 注意namespace要与thrift声明一致
  8. "namespace" => "Com\\Yourcompany\\Demo\\",
  9. ],
  10. ];

http(nova客户端)项目 配置直接tcp-server,通过 nova 存根代码调用nova服务¶

配置拉取服务

http-demo/resource/config/${env}/service_discovery.php

  1. <?php
  2.  
  3. return [
  4. # 服务Provider应用名
  5. "app_names" => [
  6. "tcp-demo"
  7. ],
  8.  
  9. "novaApi" => [
  10. // 这里配置与client相同
  11. "tcp-demo" => [
  12. "path" => "vendor/nova-service/nova-demo/sdk/gen-php",
  13. "namespace" => "Com\\Yourcompany\\Demo\\",
  14. ]
  15. ],
  16.  
  17. "connection" => [
  18. // 直连地址
  19. // 端口参见 tcp-demo/resource/config/online/server.php host & port 配置
  20. "tcp-demo" => [
  21. "host" => "127.0.0.1",
  22. "port" => 8100,
  23. ],
  24. ],
  25. ];

调用代码:

  1. <?php
  2.  
  3. namespace Com\Youzan\ZanHttpDemo\Demo\Service;
  4.  
  5.  
  6. use Com\Yourcompany\Demo\Service\DemoService;
  7.  
  8. class NovaCall
  9. {
  10.  
  11. public function invokeRemoteNovaMethod()
  12. {
  13. $result = [];
  14.  
  15. $service = new DemoService();
  16. $result['Bool'] = (yield $service->returnBool());
  17. $result['Void'] = (yield $service->returnVoid());
  18. $result['I32'] = (yield $service->returnI32());
  19. $result['Double'] = (yield $service->returnDouble());
  20. $result['String'] = (yield $service->returnString());
  21. $result['Enum'] = (yield $service->returnEnum());
  22. $result['BaseStruct'] = (yield $service->returnBaseStruct());
  23.  
  24. $result['MixedStruct'] = (yield $service->returnMixedStruct());
  25. $result['List'] = (yield $service->returnList());
  26. $result['Set'] = (yield $service->returnSet());
  27. $result['Map'] = (yield $service->returnMap());
  28.  
  29. yield $result;
  30. }
  31. }

分别启动tcp-demo、http-demo¶

tcp-demo

  1. [2017-06-05 12:31:02 #] Running in online mode
  2. [2017-06-05 20:31:02 #] server starting ..... [0.0.0.0:8100]
  3. [2017-06-05 20:31:02 #23827.0] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=0]
  4. [2017-06-05 20:31:02 #23827.1] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=1]
  5. [2017-06-05 20:31:02 #0] worker *0 starting .....
  6. [2017-06-05 20:31:02 #1] worker *1 starting .....
  7. [2017-06-05 20:31:02 #0] redis client connect to server [host=127.0.0.1, port=6379]
  8. [2017-06-05 20:31:02 #1] redis client connect to server [host=127.0.0.1, port=6379]
  9. [2017-06-05 20:31:02 #0] redis client connect to server [host=127.0.0.1, port=6379]
  10. [2017-06-05 20:31:02 #1] redis client connect to server [host=127.0.0.1, port=6379]
  11. [2017-06-05 20:31:02 #0] mysql client connect to server [host=127.0.0.1, port=3306]
  12. [2017-06-05 20:31:02 #0] mysql client connect to server [host=127.0.0.1, port=3306]
  13. [2017-06-05 20:31:02 #1] mysql client connect to server [host=127.0.0.1, port=3306]
  14. [2017-06-05 20:31:02 #1] mysql client connect to server [host=127.0.0.1, port=3306]

http-demo

  1. [2017-06-05 12:31:50 #] Running in online mode
  2. [2017-06-05 20:31:50 #23838.1] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=1]
  3. [2017-06-05 20:31:50 #23838.0] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=0]
  4. [2017-06-05 20:31:50 #] server starting .....[0.0.0.0:8030]
  5. [2017-06-05 20:31:51 #0] worker *0 starting .....
  6. [2017-06-05 20:31:51 #1] worker *1 starting .....
  7. [2017-06-05 20:31:51 #0] redis client connect to server [host=127.0.0.1, port=6379]
  8. [2017-06-05 20:31:51 #1] redis client connect to server [host=127.0.0.1, port=6379]
  9. [2017-06-05 20:31:51 #0] redis client connect to server [host=127.0.0.1, port=6379]
  10. [2017-06-05 20:31:51 #1] redis client connect to server [host=127.0.0.1, port=6379]
  11.  
  12. # 这里观察日志,已经连接到tcp-demo
  13.  
  14. [2017-06-05 20:31:51 #0] nova client connect to server [app_name=tcp-demo, host=127.0.0.1, port=8100, namespace=com.youzan.service, protocol=nova, status=1, weight=100]
  15. [2017-06-05 20:31:51 #1] nova client connect to server [app_name=tcp-demo, host=127.0.0.1, port=8100, namespace=com.youzan.service, protocol=nova, status=1, weight=100]
  16.  
  17.  
  18. [2017-06-05 20:31:51 #1] mysql client connect to server [host=127.0.0.1, port=3306]
  19. [2017-06-05 20:31:51 #0] mysql client connect to server [host=127.0.0.1, port=3306]
  20. [2017-06-05 20:31:51 #1] mysql client connect to server [host=127.0.0.1, port=3306]
  21. [2017-06-05 20:31:51 #0] mysql client connect to server [host=127.0.0.1, port=3306]

测试

curl (http)-> http-demo (nova)-> tcp-demo

curl http://127.0.0.1:8030/index/index/novaRemoteService

  1. {"code":0,"msg":"json string","data":{"Bool":true,"Void":null,"I32":768,"Double":0.17000000000000001,"String":"aaaa","Enum":2,"BaseStruct":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null},"MixedStruct":{"propString":"MixedStruct","baseStruct":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null},"propList":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"propSet":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"propMap":{"returnMixedStruct":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}}},"List":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"Set":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"Map":{"returnMap":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}}}}⏎

原文: http://zanphpdoc.zanphp.io/nova/nova_service.html