iT邦幫忙

0

Node.js - WriteFile 的非同步 Handle 問題

  • 分享至 

  • twitterImage

哈囉各位邦友們,這邊有一隻 API 是用來複製 Server 上 Shared Folder 的圖片
所以模組的部分有使用到 smb2
由於這個模組提供的皆是非同步的 function,沒有類似 fs.writeFileSync 的同步 function,所以用了 async/await 及 Promise 來達成同步
以下是複製圖片相關的 Code,圖片皆有大、中、小三張圖,複製完成後才會 send 訊息給前端去接收

function ReadPhotoFile(src) {
  return new Promise(function (resolve, reject) {
    smb2.readFile(src, function (err, data) {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  })
}
  
function WritePhotoFile(dest, data) {
  return new Promise(function(resolve, reject) {
    smb2.writeFile(dest, data, function (err, callback) {
      if (err) {
        console.log('WRITE ERROR!')
        reject(err);
      } else {
        resolve(callback);
      }
    });
  })
}
  
async function CopyFile(src, dest) {
  try {
    let data = await ReadPhotoFile(src)
    await WritePhotoFile(dest, data)
  } catch (error) {
    console.error(error);
  }
}
  
// 實際執行的部分
async function() {
//...
  await CopyFile(`${path}\\${Sketch_Month_s}\\Large\\${file_s}`, `${path}\\${Sketch_Month_d}\\Large\\${file_d}`);
  await CopyFile(`${path}\\${Sketch_Month_s}\\${file_s}`, `${path}\\${Sketch_Month_d}\\${file_d}`);
  await CopyFile(`${path}\\${Sketch_Month_s}\\Thumb\\${file_s}`, `${path}\\${Sketch_Month_d}\\Thumb\\${file_d}`);
  
  await res.send("success");
}

大部分的時候都能成功複製圖片,但偶爾會跳出以下的錯誤訊息

WRITE ERROR!
{ Error: STATUS_PENDING (0x00000103) : The operation that was requested is pending completion.
at Object.<anonymous>(D:\***\***\node_modules\smb2\lib\tools\message.js:25:21)
  at Socket.<anonymous> (D:\***\***\node_modules\smb2\lib\tools\smb2-forge.js:72:31)
  at Socket.emit (events.js:189:13)
  at addChunk (_stream_readable.js:284:12)
  at readableAddChunk (_stream_readable.js:265:11)
  at Socket.Readable.push (_stream_readable.js:220:10)
  at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17) code: 'STATUS_PENDING' }

這邊皆是複製大圖時會跳出此訊息!雖然大圖沒複製成功,但程式並不會 crash,中圖小圖皆能複製完成,並發送訊息給前端,但這個結果反而不是我們想要的

想請問這個錯誤到底是我們對於 async/await 及 Promise 的掌握度不夠?
又或者其實是 smb2 Source Code 造成的問題呢?
這個錯誤真的很困擾,煩請邦友們解答 /images/emoticon/emoticon06.gif

fillano iT邦超人 1 級 ‧ 2019-08-23 09:15:08 檢舉
https://blogs.msdn.microsoft.com/openspecification/2013/03/27/smb-2-x-and-smb-3-0-timeouts-in-windows/

系統可能會用同步或非同步操作複製的動作,如果碰到大檔,系統決定使用非同不的方式來作業,就會返回STATUS_PENDING,這是目前看到的資訊。其他可能要看一下原始碼了。
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

2
fillano
iT邦超人 1 級 ‧ 2019-08-23 09:22:23
最佳解答

從這篇文章可以看到一些SMB2/SMB3的資訊:
https://blogs.msdn.microsoft.com/openspecification/2013/03/27/smb-2-x-and-smb-3-0-timeouts-in-windows/

裡面提到怎樣會返回STATUS_PENDING,這不是失敗,而是系統通知client他要採用非同步的作業。

但是它程式處理返回的訊息是這樣寫:

https://github.com/bchelli/node-smb2/blob/master/lib/tools/message.js

var defaults = {

  successCode: 'STATUS_SUCCESS'

, parse:function(connection, cb){
...
      if(err.code == self.successCode){
      ...
      } else {
      ...
      }
...

結果就是非STATUS_SUCCESS的話就會失敗。

如果知道怎麼改,建議你改了它原始碼送PR給作者。

rchin iT邦新手 5 級 ‧ 2019-08-23 15:34:29 檢舉

感謝提點!debug 時沒有往 smb2 的協定去找資訊,一直以為 STATUS_PENDING 是 Promise 發出來的訊息 ...

1
dragonH
iT邦超人 5 級 ‧ 2019-08-23 09:30:27

codepen

所以你是想要全部 CopyFile 都沒問題

才 send message 到前端嗎

你原本的 code

用 await CopyFile

他的確有等他執行完

執行有錯誤也拿到錯誤

但是沒人跟他說有錯誤要停下來

他只會一直往下執行

我的理解啦/images/emoticon/emoticon11.gif

rchin iT邦新手 5 級 ‧ 2019-08-23 15:40:33 檢舉

我理解了,原來是我的 Code 沒有告訴它錯誤要停下來
f大回答得比較接近核心問題,真不好意思沒辦法給你最佳解答,但還是很感謝你解答了這個部分!!

dragonH iT邦超人 5 級 ‧ 2019-08-23 15:43:36 檢舉

/images/emoticon/emoticon12.gif

dragonH iT邦超人 5 級 ‧ 2019-08-23 15:51:40 檢舉

rchin

不對

你好像誤會了 fillano大 的意思

fillano大 的意思應該是說

smb2的作者誤把 STATUS_PENDING 當成 error throw 出來

也就是你看到的那個 errror

他也的確是 promise 接到 error 後發出的訊息

如果我的理解沒錯的話

我要發表回答

立即登入回答