更新4 - 为了清晰起见重新提出问题
我正在使用Pull Queues来提供发送推送通知的后端工作人员任务。我可以看到前端实例在日志中排队任务。但是,该任务仅偶尔由后端处理。我没有看到任务在处理和从队列中删除之前为什么会消失的迹象。
这可能是相关的:我在尝试从队列中租用任务时看到异常高的TransientFailureException个数 - 尽管在尝试之间休眠。
我的开发服务器上的所有内容都正常工作(早期版本已在生产中使用),但生产不再正常。起初我以为这是证书问题。但是,有时会在后端首次启动时发送通知。
当我在队列上调用leaseTasks时,除了TransientFailureException之外没有任何迹象表明发生了错误。此外,我的日志似乎需要很长时间才能显示出来。
我可以根据需要提供更多信息和代码段。
感谢您的帮助。
更新1:
该应用程序使用10个拉取队列。它通常会使用2但队列标记仍然被认为是实验性的。它们以标准方式声明:
<queue>
<name>gcm-henchdist</name>
<mode>pull</mode>
</queue>
租赁任务功能是:
public boolean processBatchOfTasks()
{
List< TaskHandle > tasks = attemptLeaseTasks();
if( null == tasks || tasks.isEmpty() )
{
return false;
}
processLeasedTasks( tasks );
return true;
}
private List< TaskHandle > attemptLeaseTasks()
{
for( int attemptNnum = 1; !LifecycleManager.getInstance().isShuttingDown(); ++attemptNnum )
{
try
{
return m_taskQueue.leaseTasks( m_numLeaseTimeUnits, m_leaseTimeUnit, m_maxTasksPerLease );
} catch( TransientFailureException exc )
{
LOG.warn( "TransientFailureException when leasing tasks from queue '{}'", m_taskQueue.getQueueName(), exc );
ApiProxy.flushLogs();
} catch( ApiDeadlineExceededException exc )
{
LOG.warn( "ApiDeadlineExceededException when when leasing tasks from queue '{}'",
m_taskQueue.getQueueName(), exc );
ApiProxy.flushLogs();
}
if( !backOff( attemptNnum ) )
{
LOG.warn( "Failed to lease tasks." );
break;
}
}
return Collections.emptyList();
}
其中租约变量为30,TimeUnit.MINUTES,分别为100
通过以下方式查询processBatchOfTasks函数:
private void startPollingForClient( EClientType clientType )
{
InterimApnsCertificateConfig config = InterimApnsCertificateConfigMgr.getConfig( clientType );
Queue notificationQueue = QueueFactory.getQueue( config.getQueueId().getName() );
ApplePushNotificationWorker worker = new ApplePushNotificationWorker(
notificationQueue,
m_messageConverter.getObjectMapper(),
config.getCertificateBytes(),
config.getPassword(),
config.isProduction() );
LOG.info( "Started worker for {} polling queue {}", clientType, notificationQueue.getQueueName() );
while ( !LifecycleManager.getInstance().isShuttingDown() )
{
boolean tasksProcessed = worker.processBatchOfTasks();
ApiProxy.flushLogs();
if ( !tasksProcessed )
{
// Wait before trying to lease tasks again.
try
{
//LOG.info( "Going to sleep" );
Thread.sleep( MILLISECONDS_TO_WAIT_WHEN_NO_TASKS_LEASED );
//LOG.info( "Waking up" );
} catch ( InterruptedException exc )
{
LOG.info( "Polling loop interrupted. Terminating loop.", exc );
return;
}
}
}
LOG.info( "Instance is shutting down" );
}
并通过以下方式创建线程:
Thread thread = ThreadManager.createBackgroundThread( new Runnable()
{
@Override
public void run()
{
startPollingForClient( clientType );
}
} );
thread.start();
GCM通知以类似的方式处理。
更新2
以下是退避功能。我在日志中验证了(包括GAE和我自己的时间戳)睡眠正在递增
private boolean backOff( int attemptNo )
{
// Exponential back off between 2 seconds and 64 seconds with jitter
// 0..1000 ms.
attemptNo = Math.min( 6, attemptNo );
int backOffTimeInSeconds = 1 << attemptNo;
long backOffTimeInMilliseconds = backOffTimeInSeconds * 1000 + (int)( Math.random() * 1000 );
LOG.info( "Backing off for {} milliseconds from queue '{}'", backOffTimeInMilliseconds, m_taskQueue.getQueueName() );
ApiProxy.flushLogs();
try
{
Thread.sleep( backOffTimeInMilliseconds );
} catch( InterruptedException e )
{
return false;
}
LOG.info( "Waking up from {} milliseconds sleep for queue '{}'", backOffTimeInMilliseconds, m_taskQueue.getQueueName() );
ApiProxy.flushLogs();
return true;
}
更新3
任务将添加到前端实例上的事务中的队列中:
if( null != queueType )
{
String deviceName;
int numDevices = deviceList.size();
for ( int iDevice = 0; iDevice < numDevices; ++iDevice )
{
deviceName = deviceList.get( iDevice ).getName();
LOG.info( "Queueing Your-Turn notification for user: {} device: {} queue: {}", user.getId(), deviceName, queueType.getName() );
Queue queue = QueueFactory.getQueue( queueType.getName() );
queue.addAsync( TaskOptions.Builder.withMethod( TaskOptions.Method.PULL )
.param( "alertLocKey", "NOTIF_YOUR_TURN" ).param( "device", deviceName ) );
}
}
我知道事务成功,因为数据库正确更新。
在日志中,我看到“排队你的转弯通知...”条目,但我看到后端日志中没有显示任何内容。
在管理面板中,我看到任务队列API调用递增1以及任务队列存储任务计数递增1.但是,写入的队列在队列中的任务和最后一分钟租用中都显示为零字段。
答案 0 :(得分:0)
TransientFailureException JavaDoc表示“如果再次尝试,请求的操作可能会成功”(因为失败是暂时的)。因此,当抛出此异常时,您的代码应循环回并重复leaseTasks调用。此外,AppEngine不必重做请求本身,因为它通过例外通知您应该这样做。
遗憾的是你重复方法名称leaseTasks作为你自己的一个,因为现在我不清楚当我提到leaseTasks时我指的是哪一个。仍然,将内部调用包含在while循环中的m_taskQueue.leaseTasks和另一个try块中以仅捕获TransientFailureException。仅当未抛出该异常时,才使用标志结束while循环。
这是足够的解释,还是需要完整的源代码列表?
答案 1 :(得分:0)
看起来罪魁祸首可能是我在排队任务时调用addAsync而不只是调用add。
我取代了电话,事情似乎一直在努力。我想知道为什么这会产生影响,并在找到原因时更新答案。