[Resolvido][VRaptor] java.net.SocketException: Connection reset by peer: socket write error

29 respostas
R

Gente, bom dia.

Eu estou com a seguinte exception quando eu faço um redirect. Mas o problema é que acontece somente em 1 método.

Os outros estão fazendo redirect normalmente…

Gostaria de entender porquê que isso acontece.

Aqui está a StackTrace:

09/04/2012 07:59:18 org.apache.catalina.core.StandardContextValve throwable AVISO: Exception Processing ErrorPage[exceptionType=java.lang.Exception, location=/erro.jsp] ClientAbortException: java.net.SocketException: Connection reset by peer: socket write error at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:333) at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:299) at org.apache.catalina.connector.Response.flushBuffer(Response.java:560) at org.apache.catalina.core.StandardContextValve.throwable(StandardContextValve.java:404) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:204) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:151) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:269) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: java.net.SocketException: Connection reset by peer: socket write error at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(Unknown Source) at java.net.SocketOutputStream.write(Unknown Source) at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:216) at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:437) at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:119) at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:721) at org.apache.coyote.Response.action(Response.java:170) at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:328) ... 16 more

29 Respostas

L

isso acontece sempre nesse método?

R

Sempre. O método é responsável por salvar um determinado registro e depois dá um redirect para uma tela que lista esses registros.

Eu percebi que o erro acontece e o VRaptor manda ele refazer a requisição, ele volta certinho, tenta inserir e dá erro pois já foi inserido.
Quando dá o erro, ele faz um redirect para outra tela, o formulário. E este segundo redirect funciona direitinho.

L

então tão acontecendo 2 redirects, certo?

tipo dá erro ao commit da transação e daí vc redireciona pra uma página de erro?

R

Não, primeiro ele insere o registro no banco e manda uma mensagem na tela informando que foi inserido e depois dá um redirect, ai é lançado o ClientAbortException.
Depois o interceptor do VRaptor captura esse erro e chama o método denovo. Passando os mesmos parametros novamente.

Nesse momento, tenta fazer o insert novamente, mas por existir campos unique, dá uma HibernateException. Quando acontece uma HibernateException, eu mando uma mensagem na view e dou um redirect para o formulário.

Esse segundo redirect não lança o ClientAbortException. Só o primeiro.

public void associar(SellerDeepSea sellerDeepSea,
			CustomerPadrao customerPadrao, AccountGroup accountGroup) {
		try {
			RelCusSelAcc obj = new RelCusSelAcc();

			obj.setAccountGroup(accountGroup);
			obj.setCustomerPadrao(customerPadrao);
			obj.setSellerDeepSea(sellerDeepSea);
			obj.setSituacao(Situacao.ATIVO);

			sellerDeepSeaDAO.saveRelacionamento(obj); // aqui não dá erro na primeira vez

			service.modal("sucesso", "objAssociado",
					".dataTables_filter input:text");
			result.redirectTo(this).listCustomer(sellerDeepSea.getCodigo()); // aqui é lançado o ClientAbortException.
		} catch (HibernateException e) {
// ClientAbortException não é tratado nesse catch
			service.modal("erro", "objNaoAssociado", "#accountGroup");
			result.redirectTo(this).associacoes(sellerDeepSea.getCodigo());// na segunda vez que fizer a requisição, vai dar HibernateException e vai executar esse redirect normalmente.
		}
	}

Outra coisa que eu percebi é que se eu inserir um catch para ClientAbortException e simplesmente não fazer nada, as requisições ficam malucas.

L

esse service.modal tenta escrever algo no response?

R

o método modal insere dados pelo result.include...
Ele nunca deu problema... Mas nunca se sabe, né.

Aqui está o codigo dele.
public void modal(String titulo, String mensagem, String onClickFocus) {
		if (this.bundle != null) {
			titulo = this.bundle.getString(titulo);
			mensagem = this.bundle.getString(mensagem);
		}

		if (onClickFocus != null && onClickFocus != "") {
			onClickFocus = "$('" + onClickFocus + "').focus();";
			this.result.include("onClickFocus", onClickFocus);
		}

		this.result.include("mensagemModal", mensagem);
		this.result.include("tituloModal", titulo);
		this.result.include("buttonFocus", "buttonConfirmar");
		this.result.include("modal", "modalOK");
	}
L

estranho… o client abort é qdo o browser desiste da requisição…

não tem mais nada que faça operações com o response? tipo um interceptor?

R

Tem sim. Isso tem a ver com o browser? Esse é um sistema corporativo e intranet que só pode ser acessado por IE8.

@Intercepts(after = FuncionalidadesInterceptor.class)
public class SetFuncionalidadesInterceptor implements Interceptor {

	private final UserWeb userWeb;
	private final Result result;

	public SetFuncionalidadesInterceptor(UserWeb userWeb, Result result) {
		this.userWeb = userWeb;
		this.result = result;
	}

	@Override
	public void intercept(InterceptorStack stack, ResourceMethod method,
			Object resourceInstance) throws InterceptionException {
		for (TipoFuncionalidade funcionalidade : userWeb
				.getFuncionalidadeList()) {
			result.include(("FUNC_" + funcionalidade.name()), true);
		}

		stack.next(method, resourceInstance);
	}

	@Override
	public boolean accepts(ResourceMethod method) {
		return (this.userWeb.getLogado());
	}
}
@Intercepts(after = ParametersInstantiatorInterceptor.class)
public class NoCacheInterceptor implements Interceptor {

	private final HttpServletResponse response;

	public NoCacheInterceptor(HttpServletResponse response) {
		this.response = response;
	}

	@Override
	public void intercept(InterceptorStack stack, ResourceMethod method,
			Object resourceInstance) throws InterceptionException {
		// set the expires to past
		response.setHeader("Expires", "Wed, 31 Dec 1969 21:00:00 GMT");

		// no-cache headers for HTTP/1.1
		response.setHeader("Cache-Control",
				"no-store, no-cache, must-revalidate");

		// no-cache headers for HTTP/1.1 (IE)
		response.addHeader("Cache-Control", "post-check=0, pre-check=0");

		// no-cache headers for HTTP/1.0
		response.setHeader("Pragma", "no-cache");

		stack.next(method, resourceInstance);
	}

	@Override
	public boolean accepts(ResourceMethod method) {
		return true;
	}

}
Se for por causa do interceptor, tem grandes chances de ser pelo NoCacheInterceptor... Mas eles estão ai há muito tempo. E em todas as outras requisições tudo funciona normalmente.
L

qdo o client abort acontece não dá o erro do hibernate, certo?

a requisição é direto pro método associar?

a requisição chega a voltar pro browser?

R

Não dá, tanto que se eu voltar para a tela de listagem, o novo registro aparece la.

Quando eu envio a requisição, ela é direto sim. Assim como quando o VRaptor refaz ela.

A requisição só volta pro browser depois que o VRaptor refaz a requisição e dá HException…

L

o vraptor refaz a requisição? ou é a aplicação que faz isso?

R

é o VRaptor. Ele cai nesse finally aqui.

public <T> T provideForRequest(RequestInfo request, Execution<T> execution) { VRaptorRequestHolder.setRequestForCurrentThread(request); REQUEST.start(); try { return execution.insideRequest(container); } finally { REQUEST.stop(); VRaptorRequestHolder.resetRequestForCurrentThread(); } }

L

mas esse código não refaz a requisição… o REQUEST.stop(); só e o cara que finaliza o escopo de request.

R

VRaptorRequestHolder.resetRequestForCurrentThread();

Esse método faz o que? Pelo nome eu pensei que ele refizesse o request. Pois logo à frente (depois de muitos f6) ele volta para o método associar.

L

ele limpa um thread local (feio, mas necessário) só isso.

R

Então quem refaz a requisição? Pois quando ele sai do método, ele passa por tudo isso e depois volta para o método…

L

será que não é a própria aplicação fazendo isso? será que ela não tá repetindo a requisição?

vc consegue fazer a requisição em outro browser, ou, melhor ainda, sem browser? (via linha de comando ou usando o poster do firefox)

R

Só pode ser o browser, testei no firefox e ele funciona lindo e bonito.
Agora é pior do que eu imaginava.

R

Então, pela exception que está dando, significa que o browser cortou a sessão no meio… Mas por que? Como é que eu arrumo isso? Agora eu fiquei completamente perdido…

L

faz um teste: tira o NoCache…Interceptor (só comenta a @Intercepts) e veja se funciona…

R

Agora ele não dá mais aquela exception, mas executa o método duas vezes…

R

Um fato interessante: TODOS os métodos dos controllers estão sendo executados duas vezes…

L

bizarro hein?

de qqer forma, o NoCache…Interceptor só precisa passar em requisições GET… em POST o browser já não cacheia por padrão.

tenta ver se não é algo na view que tá fazendo mais de uma request.

R

Como assim mais de um request? Eu coloquei um breakpoint em um método que é acessado por um não tem como esse cara fazer 2 requisições…

Eu acho que pode ser algum interceptor meu fazendo stack.next(); desnecessariamente…

R

Eu não consigo encontrar esse problema… :frowning:

Ele está executando os interceptors 2 vezes também…

Só que agora acontece o seguinte: Ele redireciona para o listCustomer() e mostra a mensagem de que deu certo.

Mas quando eu entro em qualquer tela, ele me mostra a mensagem de que não foi possível adicionar. Ou seja, ele executou duas vezes, deu HException por causa do campo unique, executou o service.modal. Mas na hora de mostrar na primeira vez, ele mostra a primeira modal, na segunda, ele mostra a segunda modal.

Está ficando confuso demais… :?

R

Ele está caindo aqui e manda um stack.next(); ai executa o método pela segunda vez…

public void execute(InterceptorStack stack, ResourceMethod method, Object resourceInstance) throws InterceptionException { Interceptor interceptor = container.instanceFor(type); if (interceptor == null) { throw new InterceptionException("Unable to instantiate interceptor for " + type.getName() + ": the container returned null."); } if (interceptor.accepts(method)) { logger.debug("Invoking interceptor {}", interceptor.getClass().getSimpleName()); interceptor.intercept(stack, method, resourceInstance); } else { stack.next(method, resourceInstance);// aqui. } }
Mas isso é certo, preciso saber quem está chamando esse cara duas vezes…

L

acontece a mesma coisa no Firefox?

R

Não… No firefox fica certinho. Executa 1 vez só… todos os métodos.

R

Consegui resolver o problema das requisições dobradas. Era um JS estragando a minha vida… Descuido total…

Quanto à exception, ela foi resolvida assim que eu setei o NoCacheInterceptor somente para requisições get.

Criado 9 de abril de 2012
Ultima resposta 9 de abr. de 2012
Respostas 29
Participantes 2