定时同步订单信息

158 阅读2分钟

有这么一个场景👇

由于网络的问题,我们创建订单并付费成功了。但是,在调用同步订单接口的时候,出现了网络的问题等不可抗拒的因素而同步不成功。这个时候,就会造成订单的状态不正确,那么,我们有什么措施解决或者减少这种情况的?

嗯~

我们可以采用下面的方案:

  1. 使用浏览器存储,将订单信息存储在 IndexedDB
  2. 将信息存储在电脑本地

使用 IndexedDB 在之前的文章中,我们已经提及 前端使用 IndexedDB 存储

这里,我们采取第二种方法 - 将信息存储在电脑磁盘。下面是我们的思路👇

这里我们使用的开发环境 👇

版本:Windows 10 专业版

版本号:22H2

电脑上拆分了多个磁盘 C, D, E, F

  1. 在同步订单的接口执行前,先将订单机器信息记录到本地
  2. 在应用的首页,每隔 * 分钟轮询本地的记录,同步到远程服务
  3. 如果同步成功,则删除本地的信息记录;同步失败的订单下次轮询

👌。思路有了,我们来实现下,这里假设你已经安装了对应的 Node 环境。

写入文件

我们将订单信息记录在 D 盘下:

export const LOCAL_DISK_ORDER_INFO_PATH = "d:\\app-name\order-info"; // 订单信息存放的路径

export interface DiskSaveOrderInfo {
  billNo: string;
  billPayTime: string;
  payWay: string
  // ... other properties
}

我们将执行下面的操作进行保存。

// 获取订单的文件路径
export const getOrderFilePath = (orderId: string) => {
  return path.join(LOCAL_DISK_ORDER_INFO_PATH, `${orderId}.json`); // 存储为 json 文件
};

// 保存订单到文件
export const saveOrderToFile = async (orderId: string, order: DiskSaveOrderInfo) => {
  const filePath = getOrderFilePath(orderId);
  // 创建文件路径
  if (!fs.existsSync(LOCAL_DISK_ORDER_INFO_PATH)) {
    try {
      // 创建对应的文件夹
      await fs.promises.mkdir(LOCAL_DISK_ORDER_INFO_PATH, { recursive: true });
    } catch (error) {
      console.error("fs.promises.mkdir", "创建目录失败", error);
    }
  } else {
    fs.writeFileSync(filePath, JSON.stringify(order, null, 2)); // 写入数据
  }
};

读取文件

我们从磁盘中读取保存的订单信息👇

// 从文件中读取订单 - 读取单个文件
export const readOrderFromFile = (orderId: string): DiskSaveOrderInfo | null => {
  const filePath = getOrderFilePath(orderId);
  try {
    const data = fs.readFileSync(filePath, "utf8");
    return JSON.parse(data);
  } catch (error) {
    console.error("fs.readFileSync", `readOrderFromFile - 读取订单 ${orderId} 失败`, error);
    return null;
  }
}

// 读取指定文件夹下的所有订单信息
export const getAllOrderFiles = (): DiskSaveOrderInfo[] => {
  try {
    const orderFiles = fs.readdirSync(LOCAL_DISK_ORDER_INFO_PATH);
    const orderFilesData = orderFiles
      .filter((file) => file.endsWith(".json"))
      .map((file) => {
        // 获取订单号
        const orderId: string = file.replace(/\.json$/, "");
        const data: DiskSaveOrderInfo | null = readOrderFromFile(orderId);
          return data;
        });
    const result = orderFilesData.filter((data) => data !== null);
    return [...result] as DiskSaveOrderInfo[];
  } catch (error) {
    console.error("getAllOrderFiles", "获取所有订单文件失败", error);
    return [];
  }
}

删除文件

我们删除磁盘上保存的订单,如下👇

// 删除订单文件
export const deleteOrderFile = (orderId: string): boolean => {
  const filePath = getOrderFilePath(orderId);
  try {
    if (fs.existsSync(filePath)) {
      fs.unlinkSync(filePath);
        return true;
    }
    return false;
  } catch (error) {
    console.error("fs.unlinkSync", `删除订单 ${orderId} 文件失败`, error);
    return false;
  }
};

执行保存

在同步订单接口之前,我们将相关的信息记录下

export function usePayDone() {
  const billNo = useStore(SelectorBillNo);
  
  const notifyPaySuccessFn = async (payWay: PayWayEnum) => {
    try {
      // 保存订单信息到本地
      await saveOrderToFile(billNo, {
        billNo,
        billPayTime: `${new Date().getTime()}`,
        payWay
      })
    } catch (error) {
      console.error("saveOrderToFile()", `保存订单 ${billNo} 信息到本地失败`, error);
    }
    // 执行同步订单到远程的代码 ...
  }
  
  return {
    notifyPaySuccessFn
  }
}

同步到远程

我们将本地的订单信息读取出来,然后依次向远程发起请求同步👇

// 定时同步本地订单的信息 - 这里可以自行实现是间隔多久触发下面的代码
export const useSyncOrders = () => {
  const handleSyncOrderFn = async () => {
    // 获取本地磁盘所有的订单信息
    const orderFiles = getAllOrderFiles();
    
    if (orderFiles.length === 0) {
      return Promise.resolve();
    }
    
    const syncPromises = orderFiles.map((file) => {
      return new Promise(async (resolve, reject) => {
        try {
          // 同步订单信息接口
          await postNotifyPaySuccess({
            billNo: file.billNo,
            payWay: file.payWay,
          });
          // 如果同步成功,则删除订单
          deleteOrderFile(file.billNo);
          resolve(true);
        } catch (error){
          console.error("deleteOrderFile()", `删除本地订单 ${file.billNo} 失败`, error);
          reject(error);
        }
      });
    });
    
    return Promise.all(sysnPromises);
  }
  
  return {
    hanleSyncOrderFn,
  };
}

至此,我们已经完成了订单信息的存储,订单的读取和订单的同步。

拜拜,Happy Coding!

参考