Roberto, além de seguir as recomendações do Xiru, eu sugiro um outro
caminho: repensar a arquitetura da sua aplicação.

Já desenvolvi muitas aplicações Zope que eram clientes de outros sistemas
pela rede, pois minha especialidade durante a Bolha (1999-2002) eram portais
de notícias que publicavam milhares de itens por dia, importadando dados de
agências de notícias variadas com os mais diversos protocolos de rede.
Aprendi que muitas vezes é uma péssima idéia usar métodos invocados pelo
Zope para fazer requisições pela rede, porque as respostas nunca são
instantâneas e às vezes podem demorar muito (ou nunca chegar). Usar timeout
como o Xiru recomendou alivia este problema, mas não resolve realmente.
Porque o problema é que, enquanto o seu External Method ou Product está
esperando uma resposta da rede, ele está travando uma das pouquíssimas
threads do seu servidor Zope. Estas threads, além de escassas, são recursos
muito caros, porque elas rodam dentro do suntuoso contexto de aplicação do
Zope, que ocupa muita memória por conta de tudo o que oferece. Enfim, usar
threads do Zope para acessar servidores externos é algo que -- se possível
-- deve ser evitado, porque pode prejudicar enormemente a escalabilidade da
sua aplicação.

Então, o que fazer? A solução que sempre funcionou bem para os sites de
notícias foi delegar o acesso à rede a um processo independente do Zope,
tipicamente um script python não integrado ao Zope (não um External Method,
mas simplesmente um arquivo .py invocado pela linha de comando, que portanto
usará outro processo python para rodar).

Vamos chamar este processo independente de gandula (aquele cara que recupera
as bolas, de forma assíncrona -- sem interromper o jogo). O Zope coloca as
requisições que precisam ser feitas em uma fila (um DB relacional é ótimo
para isso), e o gandula verifica esta fila periodicamente (pode ser uma vez
por segundo), para ver se tem requisições pendentes. Para cada uma delas, o
gandula faz o acesso ao servidor externo, e de posse do resultado, acessa o
Zope via HTTP POST para entregar os dados recebidos. Assim, nenhuma thread
do Zope fica parada esperando o resultado. Se o gandula têm muita demanda, é
melhor não enfileirar os requests porque se não basta um servidor demorar
para responder para o backlog inchar. O ideal é dispará-los de forma
assíncrona. Para isso, vale a pena usar o módulo Asyncore ou o framework
Twisted para implementar um gandula mais eficiente.

Com certeza, tudo isso é mais complicado que escrever um External Method
para abrir um Socket. Mas além de complicado, é também muito mais escalável.

[ ]s
Luciano

Responder a