草庐IT

java - Jersey @ManagedAsync 并在 HTTP 线程和工作线程之间复制数据

coder 2024-03-02 原文

我正在从事一个项目,该项目有两种风格,有和没有 Multi-Tenancy 。

该项目公开了一个我希望异步的 REST 服务。 所以我的基本服务看起来像

@Component
@Path("/resouce")
@Consumes(MediaType.APPLICATION_JSON)
public class ResouceEndpoint {
    @POST
    @ManagedAsync
    public void add(final Event event, @Suspended final AsyncResponse asyncResponse) {
        resouce.insert (event);
        asyncResponse.resume( Response.status(Response.Status.NO_CONTENT).build());     
    }
}

在没有 Multi-Tenancy 的情况下工作正常,我免费获得了内部 Jersey 执行程序服务的好处。参见 @ManagedAsync

当我切换到 Multi-Tenancy 时,我在解析租户 ID 的请求上添加了一个过滤器,并将其放在本地线程(在我们的例子中是 HTTP 线程)上。

当处理链命中“add()”方法时,当前线程是 Jersey 执行器服务提供的线程,因此它不包括我的租户 ID。 我只能考虑以下选项来解决此问题。

将 ResouceEndpoint 扩展为 MutliTenantResouceEndpoint 并删除 @ManagedAsync 使用我自己的线程执行器

public class MutliTenantResouceEndpoint extends ResouceEndpoint {
    @POST
    public void add(final Event event, @Suspended final AsyncResponse asyncResponse) {
        final String tenantId = getTeantIdFromThreadLocal();
        taskExecutor.submit(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                setTeantIdToThreadLocal(tenantId);
                browserEventsAnalyzer.insertEvent(event);
                Response response = Response.status(Response.Status.NO_CONTENT).build();
                asyncResponse.resume(response);
                return null;
            }
        });
    }
}

但是通过这种方式我需要管理我自己的线程执行器,感觉就像我在这里遗漏了一些东西。 有什么关于不同方法的建议吗?

最佳答案

这里有一些建议,按顺序排列。

就上下文而言,我已经使用 Jersey 2 年了,并且在 18 个月前就遇到了这个确切的问题。

1。停止使用 @ManagedAsync

如果您可以控制运行 Jersey 的 http 服务器,我建议您停止使用 @ManagedAsync

与其设置 Jersey 立即返回它的 http 处理线程并将实际请求工作卸载到托管执行程序服务线程,不如使用类似 Grizzly 的东西为您的 http 服务器,并将其配置为具有更大的工作线程池。这完成了同样的事情,但是将异步责任推到了 Jersey 下面的一层。

如果您将 @ManagedAsync 用于任何大中型项目,那么在一年的时间里您会遇到很多痛点。以下是我脑海中浮现的一些内容:

  • 如果任何 ContainerRequestFilter 命中外部服务(例如,auth 过滤器命中您的安全模块,后者命中数据库),您将失去您认为获得的好处
    • 如果您的数据库阻塞并且 auth 过滤器调用需要 5 秒,则 Jersey 尚未将工作卸载到异步线程,因此您需要接收新连接的主线程被阻塞
  • 如果您在过滤器中设置 logback 的 MDC,并且希望在整个请求中使用该上下文,则需要在托管异步线程上再次设置 MDC
  • 资源方法对于新手来说是晦涩难懂的,因为:
    • 他们需要一个额外的参数
    • 他们返回 void,隐藏他们真正的响应类型
    • 他们可以在任何地方“返回”,而无需任何实际的return语句
  • Swagger 或其他 API 文档工具无法自动记录异步资源端点
  • Guice 或其他 DI 框架可能无法处理异步资源端点中的某些范围绑定(bind)和/或提供程序

2。使用 @ContextContainerRequest 属性

这将涉及在您的过滤器中调用 requestContext.setProperty("tenant_id", tenantId),然后在您的资源中调用 requestContext.getProperty("tenant_id")使用 @Context 注入(inject)请求。

3。使用 HK2 AOP 代替 Jersey 过滤器

这将涉及设置 InterceptionService 的 HK2 绑定(bind),它有一个 MethodInterceptor 检查托管异步资源方法并手动执行所有 RequestScoped绑定(bind) ContainerRequestFilter。你的过滤器不是在 Jersey 注册的,而是在 HK2 注册的,由方法拦截器运行。

如果您愿意,我可以向选项 2/3 添加更多详细信息和代码示例,或者提供其他建议,但首先查看更多过滤器代码会有所帮助,如果可能,我再次建议选项 1。

关于java - Jersey @ManagedAsync 并在 HTTP 线程和工作线程之间复制数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31137134/

有关java - Jersey @ManagedAsync 并在 HTTP 线程和工作线程之间复制数据的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  5. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  8. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  9. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  10. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

随机推荐