Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/RuntimeBaseCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,19 @@ class RuntimeBaseCommand extends Command {

if (err) {
let pretty = err.message || ''
if (err.name === 'OpenWhiskError') {
const connectionErrors = [err, err.error, err.cause]
const isConnectionReset = connectionErrors.some(error => {
if (!error) return false
return error.code === 'ECONNRESET' ||
/ECONNRESET/i.test(error.message || '') ||
/socket hang up/i.test(error.message || '') ||
/(ECONNRESET|socket hang up)/i.test(typeof error.error === 'string' ? error.error : '')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make the logic more cleaner by something like this -

const CONNECTION_RESET_PATTERN = /ECONNRESET|socket hang up/i const matchesConnectionReset = (value) => typeof value === 'string' && CONNECTION_RESET_PATTERN.test(value)

Then use above in error check as

e.code === ECONNRESET || matchesConnectionReset(e.message) || matchesConnectionReset(e.error) || matchesConnectionReset(e)

WDYT?

})

if (isConnectionReset) {
pretty = 'the connection to the Runtime API was interrupted (socket hang up / ECONNRESET). ' +
'Please try again in a few moments. Before you do, run `aio app use` to get the latest Adobe Developer Console configuration file.'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Before you do, run aio app use to get the latest Adobe Developer Console configuration file."
Is this a required step or only required when workspace/runtime details are not available?
Right now the message looks like mandating the aio app:use command

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No.  Using the AIO app is a troubleshooting suggestion, not a required step for every connection reset. It may help if the project’s Adobe Developer Console configuration is stale or doesn’t match the intended workspace/runtime.

} else if (err.name === 'OpenWhiskError') {
if (err.error && err.error.error) {
pretty = err.error.error.toLowerCase()
if (err.statusCode) pretty = `${pretty} (${getStatusCode(err.statusCode)})`
Expand Down
26 changes: 26 additions & 0 deletions test/RuntimeBaseCommand.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,32 @@ describe('instance methods', () => {
expect(command.error).toHaveBeenCalledWith('msg: an error' + suffix)
})

test('connection reset gives actionable Runtime API guidance', async () => {
command.error = jest.fn()
const cause = Object.assign(new Error('read ECONNRESET'), { code: 'ECONNRESET' })
const err = new OpenWhiskError('Unknown Error From API: read ECONNRESET', cause)

await command.handleError('failed to list the activations', err)

expect(command.error).toHaveBeenCalledWith(
'failed to list the activations: the connection to the Runtime API was interrupted (socket hang up / ECONNRESET). ' +
'Please try again in a few moments. Before you do, run `aio app use` to get the latest Adobe Developer Console configuration file.' +
suffix
)
})

test('socket hang up gives actionable Runtime API guidance', async () => {
command.error = jest.fn()

await command.handleError('failed to list the activations', new Error('socket hang up'))

expect(command.error).toHaveBeenCalledWith(
'failed to list the activations: the connection to the Runtime API was interrupted (socket hang up / ECONNRESET). ' +
'Please try again in a few moments. Before you do, run `aio app use` to get the latest Adobe Developer Console configuration file.' +
suffix
)
})

test('openwhisk error, with internal error', async () => {
command.error = jest.fn()
const err = new Error('is')
Expand Down
Loading